2010-09-28 14:42:05 +00:00
|
|
|
/*
|
2011-09-30 18:15:37 +00:00
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
2010-09-28 14:42:05 +00:00
|
|
|
*
|
2017-05-01 18:42:18 +00:00
|
|
|
* Copyright (C) 1992-2017 <Jean-Pierre Charras>
|
|
|
|
* Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
|
2010-09-28 14:42:05 +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-10-17 20:01:27 +00:00
|
|
|
/**
|
|
|
|
* @file class_gerber_draw_item.cpp
|
|
|
|
*/
|
|
|
|
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <fctsys.h>
|
|
|
|
#include <gr_basic.h>
|
|
|
|
#include <common.h>
|
|
|
|
#include <trigo.h>
|
|
|
|
#include <class_drawpanel.h>
|
2013-01-12 17:32:24 +00:00
|
|
|
#include <msgpanel.h>
|
2014-06-27 17:07:42 +00:00
|
|
|
#include <gerbview_frame.h>
|
2016-05-25 09:45:55 +00:00
|
|
|
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <class_gerber_draw_item.h>
|
2016-05-25 14:48:38 +00:00
|
|
|
#include <class_gerber_file_image.h>
|
2016-09-07 08:28:16 +00:00
|
|
|
#include <class_gerber_file_image_list.h>
|
2010-09-28 14:42:05 +00:00
|
|
|
|
|
|
|
|
2016-05-26 11:57:43 +00:00
|
|
|
GERBER_DRAW_ITEM::GERBER_DRAW_ITEM( GERBER_FILE_IMAGE* aGerberImageFile ) :
|
|
|
|
EDA_ITEM( (EDA_ITEM*)NULL, TYPE_GERBER_DRAW_ITEM )
|
2010-09-28 14:42:05 +00:00
|
|
|
{
|
2016-05-26 07:50:49 +00:00
|
|
|
m_GerberImageFile = aGerberImageFile;
|
2010-10-09 20:05:03 +00:00
|
|
|
m_Shape = GBR_SEGMENT;
|
|
|
|
m_Flashed = false;
|
|
|
|
m_DCode = 0;
|
|
|
|
m_UnitsMetric = false;
|
2010-10-03 15:39:06 +00:00
|
|
|
m_LayerNegative = false;
|
2010-10-09 20:05:03 +00:00
|
|
|
m_swapAxis = false;
|
|
|
|
m_mirrorA = false;
|
|
|
|
m_mirrorB = false;
|
|
|
|
m_drawScale.x = m_drawScale.y = 1.0;
|
2010-10-17 16:42:06 +00:00
|
|
|
m_lyrRotation = 0;
|
2016-09-07 08:28:16 +00:00
|
|
|
|
2016-05-26 07:50:49 +00:00
|
|
|
if( m_GerberImageFile )
|
2010-10-09 20:05:03 +00:00
|
|
|
SetLayerParameters();
|
2010-09-28 14:42:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GERBER_DRAW_ITEM::~GERBER_DRAW_ITEM()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-16 10:56:20 +00:00
|
|
|
void GERBER_DRAW_ITEM::SetNetAttributes( const GBR_NETLIST_METADATA& aNetAttributes )
|
|
|
|
{
|
|
|
|
m_netAttributes = aNetAttributes;
|
|
|
|
|
|
|
|
if( ( m_netAttributes.m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_CMP ) ||
|
|
|
|
( m_netAttributes.m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_PAD ) )
|
|
|
|
m_GerberImageFile->m_ComponentsList.insert( std::make_pair( m_netAttributes.m_Cmpref, 0 ) );
|
|
|
|
|
|
|
|
if( ( m_netAttributes.m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_NET ) )
|
|
|
|
m_GerberImageFile->m_NetnamesList.insert( std::make_pair( m_netAttributes.m_Netname, 0 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-26 11:57:43 +00:00
|
|
|
int GERBER_DRAW_ITEM::GetLayer() const
|
|
|
|
{
|
|
|
|
// returns the layer this item is on, or 0 if the m_GerberImageFile is NULL.
|
|
|
|
return m_GerberImageFile ? m_GerberImageFile->m_GraphicLayer : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-10 19:47:44 +00:00
|
|
|
wxPoint GERBER_DRAW_ITEM::GetABPosition( const wxPoint& aXYPosition ) const
|
2010-10-09 20:05:03 +00:00
|
|
|
{
|
|
|
|
/* Note: RS274Xrevd_e is obscure about the order of transforms:
|
|
|
|
* For instance: Rotation must be made after or before mirroring ?
|
2010-10-10 17:57:54 +00:00
|
|
|
* Note: if something is changed here, GetYXPosition must reflect changes
|
2010-10-09 20:05:03 +00:00
|
|
|
*/
|
2016-05-26 07:50:49 +00:00
|
|
|
wxPoint abPos = aXYPosition + m_GerberImageFile->m_ImageJustifyOffset;
|
2010-10-09 20:05:03 +00:00
|
|
|
|
|
|
|
if( m_swapAxis )
|
2015-06-26 13:41:56 +00:00
|
|
|
std::swap( abPos.x, abPos.y );
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2016-05-26 07:50:49 +00:00
|
|
|
abPos += m_layerOffset + m_GerberImageFile->m_ImageOffset;
|
// 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
|
|
|
abPos.x = KiROUND( abPos.x * m_drawScale.x );
|
|
|
|
abPos.y = KiROUND( abPos.y * m_drawScale.y );
|
2016-05-26 07:50:49 +00:00
|
|
|
double rotation = m_lyrRotation * 10 + m_GerberImageFile->m_ImageRotation * 10;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-16 14:51:22 +00:00
|
|
|
if( rotation )
|
|
|
|
RotatePoint( &abPos, -rotation );
|
2010-10-17 16:42:06 +00:00
|
|
|
|
|
|
|
// Negate A axis if mirrored
|
2010-10-09 20:05:03 +00:00
|
|
|
if( m_mirrorA )
|
2015-06-26 13:41:56 +00:00
|
|
|
abPos.x = -abPos.x;
|
2010-10-16 14:51:22 +00:00
|
|
|
|
2010-10-17 16:42:06 +00:00
|
|
|
// abPos.y must be negated when no mirror, because draw axis is top to bottom
|
2010-10-10 17:57:54 +00:00
|
|
|
if( !m_mirrorB )
|
2015-06-26 13:41:56 +00:00
|
|
|
abPos.y = -abPos.y;
|
2010-10-09 20:05:03 +00:00
|
|
|
return abPos;
|
|
|
|
}
|
|
|
|
|
2010-10-16 14:51:22 +00:00
|
|
|
|
2014-05-04 17:08:36 +00:00
|
|
|
wxPoint GERBER_DRAW_ITEM::GetXYPosition( const wxPoint& aABPosition ) const
|
2010-10-10 17:57:54 +00:00
|
|
|
{
|
2011-10-17 20:01:27 +00:00
|
|
|
// do the inverse transform made by GetABPosition
|
2010-10-16 14:51:22 +00:00
|
|
|
wxPoint xyPos = aABPosition;
|
2010-10-10 17:57:54 +00:00
|
|
|
|
|
|
|
if( m_mirrorA )
|
2015-06-26 13:41:56 +00:00
|
|
|
xyPos.x = -xyPos.x;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-10 17:57:54 +00:00
|
|
|
if( !m_mirrorB )
|
2015-06-26 13:41:56 +00:00
|
|
|
xyPos.y = -xyPos.y;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2016-05-26 07:50:49 +00:00
|
|
|
double rotation = m_lyrRotation * 10 + m_GerberImageFile->m_ImageRotation * 10;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-16 14:51:22 +00:00
|
|
|
if( rotation )
|
|
|
|
RotatePoint( &xyPos, rotation );
|
2011-10-17 20:01:27 +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
|
|
|
xyPos.x = KiROUND( xyPos.x / m_drawScale.x );
|
|
|
|
xyPos.y = KiROUND( xyPos.y / m_drawScale.y );
|
2016-05-26 07:50:49 +00:00
|
|
|
xyPos -= m_layerOffset + m_GerberImageFile->m_ImageOffset;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-10 17:57:54 +00:00
|
|
|
if( m_swapAxis )
|
2015-06-26 13:41:56 +00:00
|
|
|
std::swap( xyPos.x, xyPos.y );
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2016-05-26 07:50:49 +00:00
|
|
|
return xyPos - m_GerberImageFile->m_ImageJustifyOffset;
|
2010-10-10 17:57:54 +00:00
|
|
|
}
|
2010-10-09 20:05:03 +00:00
|
|
|
|
2010-10-16 14:51:22 +00:00
|
|
|
|
2010-10-09 20:05:03 +00:00
|
|
|
void GERBER_DRAW_ITEM::SetLayerParameters()
|
|
|
|
{
|
2016-05-26 07:50:49 +00:00
|
|
|
m_UnitsMetric = m_GerberImageFile->m_GerbMetric;
|
|
|
|
m_swapAxis = m_GerberImageFile->m_SwapAxis; // false if A = X, B = Y;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-16 14:51:22 +00:00
|
|
|
// true if A =Y, B = Y
|
2016-05-26 07:50:49 +00:00
|
|
|
m_mirrorA = m_GerberImageFile->m_MirrorA; // true: mirror / axe A
|
|
|
|
m_mirrorB = m_GerberImageFile->m_MirrorB; // true: mirror / axe B
|
|
|
|
m_drawScale = m_GerberImageFile->m_Scale; // A and B scaling factor
|
|
|
|
m_layerOffset = m_GerberImageFile->m_Offset; // Offset from OF command
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-16 14:51:22 +00:00
|
|
|
// Rotation from RO command:
|
2016-05-26 07:50:49 +00:00
|
|
|
m_lyrRotation = m_GerberImageFile->m_LocalRotation;
|
|
|
|
m_LayerNegative = m_GerberImageFile->GetLayerParams().m_LayerNegative;
|
2010-10-09 20:05:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-28 14:42:05 +00:00
|
|
|
wxString GERBER_DRAW_ITEM::ShowGBRShape()
|
|
|
|
{
|
|
|
|
switch( m_Shape )
|
|
|
|
{
|
|
|
|
case GBR_SEGMENT:
|
|
|
|
return _( "Line" );
|
|
|
|
|
|
|
|
case GBR_ARC:
|
|
|
|
return _( "Arc" );
|
|
|
|
|
|
|
|
case GBR_CIRCLE:
|
|
|
|
return _( "Circle" );
|
|
|
|
|
|
|
|
case GBR_SPOT_OVAL:
|
|
|
|
return wxT( "spot_oval" );
|
|
|
|
|
|
|
|
case GBR_SPOT_CIRCLE:
|
|
|
|
return wxT( "spot_circle" );
|
|
|
|
|
|
|
|
case GBR_SPOT_RECT:
|
|
|
|
return wxT( "spot_rect" );
|
|
|
|
|
2010-09-28 19:34:16 +00:00
|
|
|
case GBR_SPOT_POLY:
|
|
|
|
return wxT( "spot_poly" );
|
|
|
|
|
2010-09-28 14:42:05 +00:00
|
|
|
case GBR_POLYGON:
|
|
|
|
return wxT( "polygon" );
|
|
|
|
|
2010-09-28 19:34:16 +00:00
|
|
|
case GBR_SPOT_MACRO:
|
2010-10-25 07:43:50 +00:00
|
|
|
{
|
|
|
|
wxString name = wxT( "apt_macro" );
|
|
|
|
D_CODE* dcode = GetDcodeDescr();
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-25 07:43:50 +00:00
|
|
|
if( dcode && dcode->GetMacro() )
|
|
|
|
name << wxT(" ") << dcode->GetMacro()->name;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-25 07:43:50 +00:00
|
|
|
return name;
|
|
|
|
}
|
2010-09-28 14:42:05 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
return wxT( "??" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
D_CODE* GERBER_DRAW_ITEM::GetDcodeDescr()
|
|
|
|
{
|
|
|
|
if( (m_DCode < FIRST_DCODE) || (m_DCode > LAST_DCODE) )
|
|
|
|
return NULL;
|
2014-11-22 11:52:57 +00:00
|
|
|
|
2016-05-26 07:50:49 +00:00
|
|
|
if( m_GerberImageFile == NULL )
|
2010-09-28 14:42:05 +00:00
|
|
|
return NULL;
|
|
|
|
|
2016-05-26 07:50:49 +00:00
|
|
|
return m_GerberImageFile->GetDCODE( m_DCode, false );
|
2010-09-28 14:42:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-24 17:48:14 +00:00
|
|
|
const EDA_RECT GERBER_DRAW_ITEM::GetBoundingBox() const
|
2010-09-28 14:42:05 +00:00
|
|
|
{
|
|
|
|
// return a rectangle which is (pos,dim) in nature. therefore the +1
|
2011-03-29 19:33:07 +00:00
|
|
|
EDA_RECT bbox( m_Start, wxSize( 1, 1 ) );
|
2010-09-28 14:42:05 +00:00
|
|
|
|
|
|
|
bbox.Inflate( m_Size.x / 2, m_Size.y / 2 );
|
2010-10-10 17:57:54 +00:00
|
|
|
|
2016-06-15 08:26:41 +00:00
|
|
|
// calculate the corners coordinates in current gerber axis orientations
|
|
|
|
wxPoint org = GetABPosition( bbox.GetOrigin() );
|
|
|
|
wxPoint end = GetABPosition( bbox.GetEnd() );
|
|
|
|
|
|
|
|
// Set the corners position:
|
|
|
|
bbox.SetOrigin( org );
|
|
|
|
bbox.SetEnd( end );
|
|
|
|
bbox.Normalize();
|
|
|
|
|
2010-09-28 14:42:05 +00:00
|
|
|
return bbox;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-15 18:59:26 +00:00
|
|
|
void GERBER_DRAW_ITEM::MoveAB( const wxPoint& aMoveVector )
|
2010-09-28 14:42:05 +00:00
|
|
|
{
|
2010-10-10 17:57:54 +00:00
|
|
|
wxPoint xymove = GetXYPosition( aMoveVector );
|
2010-10-16 14:51:22 +00:00
|
|
|
|
2010-10-10 17:57:54 +00:00
|
|
|
m_Start += xymove;
|
|
|
|
m_End += xymove;
|
|
|
|
m_ArcCentre += xymove;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-09-28 14:42:05 +00:00
|
|
|
for( unsigned ii = 0; ii < m_PolyCorners.size(); ii++ )
|
2010-10-10 17:57:54 +00:00
|
|
|
m_PolyCorners[ii] += xymove;
|
2010-09-28 14:42:05 +00:00
|
|
|
}
|
|
|
|
|
2010-10-16 14:51:22 +00:00
|
|
|
|
2010-10-15 18:59:26 +00:00
|
|
|
void GERBER_DRAW_ITEM::MoveXY( const wxPoint& aMoveVector )
|
|
|
|
{
|
|
|
|
m_Start += aMoveVector;
|
|
|
|
m_End += aMoveVector;
|
|
|
|
m_ArcCentre += aMoveVector;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-15 18:59:26 +00:00
|
|
|
for( unsigned ii = 0; ii < m_PolyCorners.size(); ii++ )
|
|
|
|
m_PolyCorners[ii] += aMoveVector;
|
|
|
|
}
|
2010-09-28 14:42:05 +00:00
|
|
|
|
2010-10-16 14:51:22 +00:00
|
|
|
|
2010-12-15 20:15:24 +00:00
|
|
|
bool GERBER_DRAW_ITEM::HasNegativeItems()
|
|
|
|
{
|
2016-05-26 07:50:49 +00:00
|
|
|
bool isClear = m_LayerNegative ^ m_GerberImageFile->m_ImageNegative;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-12-15 20:15:24 +00:00
|
|
|
// if isClear is true, this item has negative shape
|
2016-06-03 16:42:24 +00:00
|
|
|
return isClear;
|
2010-12-15 20:15:24 +00:00
|
|
|
}
|
|
|
|
|
2010-09-28 14:42:05 +00:00
|
|
|
|
2012-09-01 13:38:27 +00:00
|
|
|
void GERBER_DRAW_ITEM::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode,
|
2016-06-02 09:30:39 +00:00
|
|
|
const wxPoint& aOffset, GBR_DISPLAY_OPTIONS* aDrawOptions )
|
2010-09-28 14:42:05 +00:00
|
|
|
{
|
2011-10-17 20:01:27 +00:00
|
|
|
// used when a D_CODE is not found. default D_CODE to draw a flashed item
|
|
|
|
static D_CODE dummyD_CODE( 0 );
|
2010-09-28 14:42:05 +00:00
|
|
|
bool isFilled;
|
|
|
|
int radius;
|
|
|
|
int halfPenWidth;
|
|
|
|
static bool show_err;
|
|
|
|
D_CODE* d_codeDescr = GetDcodeDescr();
|
|
|
|
|
|
|
|
if( d_codeDescr == NULL )
|
|
|
|
d_codeDescr = &dummyD_CODE;
|
|
|
|
|
2017-02-20 16:57:41 +00:00
|
|
|
COLOR4D color = m_GerberImageFile->GetPositiveDrawColor();
|
2010-10-03 15:39:06 +00:00
|
|
|
|
2017-02-20 16:57:41 +00:00
|
|
|
if( ( aDrawMode & GR_HIGHLIGHT ) && !( aDrawMode & GR_AND ) )
|
|
|
|
color.SetToLegacyHighlightColor();
|
2010-09-28 14:42:05 +00:00
|
|
|
|
2010-10-16 14:51:22 +00:00
|
|
|
/* isDark is true if flash is positive and should use a drawing
|
|
|
|
* color other than the background color, else use the background color
|
|
|
|
* when drawing so that an erasure happens.
|
|
|
|
*/
|
2016-05-26 07:50:49 +00:00
|
|
|
bool isDark = !(m_LayerNegative ^ m_GerberImageFile->m_ImageNegative);
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-16 14:51:22 +00:00
|
|
|
if( !isDark )
|
2010-10-03 15:39:06 +00:00
|
|
|
{
|
2010-10-16 14:51:22 +00:00
|
|
|
// draw in background color ("negative" color)
|
2016-06-03 16:42:24 +00:00
|
|
|
color = aDrawOptions->m_NegativeDrawColor;
|
2010-09-28 14:42:05 +00:00
|
|
|
}
|
|
|
|
|
2010-10-01 19:11:30 +00:00
|
|
|
GRSetDrawMode( aDC, aDrawMode );
|
2010-09-28 14:42:05 +00:00
|
|
|
|
2016-06-02 09:30:39 +00:00
|
|
|
isFilled = aDrawOptions->m_DisplayLinesFill;
|
2010-09-28 14:42:05 +00:00
|
|
|
|
|
|
|
switch( m_Shape )
|
|
|
|
{
|
|
|
|
case GBR_POLYGON:
|
2016-06-02 09:30:39 +00:00
|
|
|
isFilled = aDrawOptions->m_DisplayPolygonsFill;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-16 14:51:22 +00:00
|
|
|
if( !isDark )
|
2010-09-28 14:42:05 +00:00
|
|
|
isFilled = true;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2011-12-29 20:11:42 +00:00
|
|
|
DrawGbrPoly( aPanel->GetClipBox(), aDC, color, aOffset, isFilled );
|
2010-09-28 14:42:05 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GBR_CIRCLE:
|
2013-05-01 17:32:36 +00:00
|
|
|
radius = KiROUND( GetLineLength( m_Start, m_End ) );
|
2010-09-28 14:42:05 +00:00
|
|
|
|
|
|
|
halfPenWidth = m_Size.x >> 1;
|
|
|
|
|
2010-09-29 19:58:22 +00:00
|
|
|
if( !isFilled )
|
2010-09-28 14:42:05 +00:00
|
|
|
{
|
|
|
|
// draw the border of the pen's path using two circles, each as narrow as possible
|
2011-12-29 20:11:42 +00:00
|
|
|
GRCircle( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
|
2010-10-09 20:05:03 +00:00
|
|
|
radius - halfPenWidth, 0, color );
|
2011-12-29 20:11:42 +00:00
|
|
|
GRCircle( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
|
2010-10-09 20:05:03 +00:00
|
|
|
radius + halfPenWidth, 0, color );
|
2010-09-28 14:42:05 +00:00
|
|
|
}
|
2010-09-29 19:58:22 +00:00
|
|
|
else // Filled mode
|
2010-09-28 14:42:05 +00:00
|
|
|
{
|
2011-12-29 20:11:42 +00:00
|
|
|
GRCircle( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
|
2010-10-09 20:05:03 +00:00
|
|
|
radius, m_Size.x, color );
|
2010-09-28 14:42:05 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GBR_ARC:
|
2011-04-23 19:01:41 +00:00
|
|
|
// Currently, arcs plotted with a rectangular aperture are not supported.
|
2010-10-25 07:43:50 +00:00
|
|
|
// a round pen only is expected.
|
2011-10-17 20:01:27 +00:00
|
|
|
|
|
|
|
#if 0 // for arc debug only
|
2011-12-29 20:11:42 +00:00
|
|
|
GRLine( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
|
2010-10-16 14:51:22 +00:00
|
|
|
GetABPosition( m_ArcCentre ), 0, color );
|
2011-12-29 20:11:42 +00:00
|
|
|
GRLine( aPanel->GetClipBox(), aDC, GetABPosition( m_End ),
|
2010-10-16 14:51:22 +00:00
|
|
|
GetABPosition( m_ArcCentre ), 0, color );
|
2010-10-11 20:57:25 +00:00
|
|
|
#endif
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-09-28 14:42:05 +00:00
|
|
|
if( !isFilled )
|
|
|
|
{
|
2011-12-29 20:11:42 +00:00
|
|
|
GRArc1( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
|
2010-10-09 20:05:03 +00:00
|
|
|
GetABPosition( m_End ), GetABPosition( m_ArcCentre ),
|
|
|
|
0, color );
|
2010-09-28 14:42:05 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-12-29 20:11:42 +00:00
|
|
|
GRArc1( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
|
2010-10-09 20:05:03 +00:00
|
|
|
GetABPosition( m_End ), GetABPosition( m_ArcCentre ),
|
2010-09-28 14:42:05 +00:00
|
|
|
m_Size.x, color );
|
|
|
|
}
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-09-28 14:42:05 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GBR_SPOT_CIRCLE:
|
|
|
|
case GBR_SPOT_RECT:
|
|
|
|
case GBR_SPOT_OVAL:
|
2010-09-28 19:34:16 +00:00
|
|
|
case GBR_SPOT_POLY:
|
2010-10-01 19:11:30 +00:00
|
|
|
case GBR_SPOT_MACRO:
|
2016-06-02 09:30:39 +00:00
|
|
|
isFilled = aDrawOptions->m_DisplayFlashedItemsFill;
|
2016-06-03 16:42:24 +00:00
|
|
|
d_codeDescr->DrawFlashedShape( this, aPanel->GetClipBox(), aDC, color,
|
2010-09-28 14:42:05 +00:00
|
|
|
m_Start, isFilled );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GBR_SEGMENT:
|
2010-10-25 07:43:50 +00:00
|
|
|
/* Plot a line from m_Start to m_End.
|
|
|
|
* Usually, a round pen is used, but some gerber files use a rectangular pen
|
|
|
|
* In fact, any aperture can be used to plot a line.
|
|
|
|
* currently: only a square pen is handled (I believe using a polygon gives a strange plot).
|
|
|
|
*/
|
|
|
|
if( d_codeDescr->m_Shape == APT_RECT )
|
|
|
|
{
|
|
|
|
if( m_PolyCorners.size() == 0 )
|
|
|
|
ConvertSegmentToPolygon( );
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2011-12-29 20:11:42 +00:00
|
|
|
DrawGbrPoly( aPanel->GetClipBox(), aDC, color, aOffset, isFilled );
|
2010-10-25 07:43:50 +00:00
|
|
|
}
|
2010-09-28 14:42:05 +00:00
|
|
|
else
|
2010-10-25 07:43:50 +00:00
|
|
|
{
|
|
|
|
if( !isFilled )
|
|
|
|
{
|
2011-12-29 20:11:42 +00:00
|
|
|
GRCSegm( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
|
2010-10-09 20:05:03 +00:00
|
|
|
GetABPosition( m_End ), m_Size.x, color );
|
2010-10-25 07:43:50 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-12-29 20:11:42 +00:00
|
|
|
GRFilledSegment( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
|
2010-10-25 07:43:50 +00:00
|
|
|
GetABPosition( m_End ), m_Size.x, color );
|
|
|
|
}
|
|
|
|
}
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-09-28 14:42:05 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if( !show_err )
|
|
|
|
{
|
|
|
|
wxMessageBox( wxT( "Trace_Segment() type error" ) );
|
2011-10-17 20:01:27 +00:00
|
|
|
show_err = true;
|
2010-09-28 14:42:05 +00:00
|
|
|
}
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-09-28 14:42:05 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-25 07:43:50 +00:00
|
|
|
void GERBER_DRAW_ITEM::ConvertSegmentToPolygon( )
|
|
|
|
{
|
|
|
|
m_PolyCorners.clear();
|
|
|
|
m_PolyCorners.reserve(6);
|
|
|
|
|
|
|
|
wxPoint start = m_Start;
|
|
|
|
wxPoint end = m_End;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-25 07:43:50 +00:00
|
|
|
// make calculations more easy if ensure start.x < end.x
|
|
|
|
// (only 2 quadrants to consider)
|
|
|
|
if( start.x > end.x )
|
2015-06-26 13:41:56 +00:00
|
|
|
std::swap( start, end );
|
2010-10-25 07:43:50 +00:00
|
|
|
|
|
|
|
// calculate values relative to start point:
|
|
|
|
wxPoint delta = end - start;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-25 07:43:50 +00:00
|
|
|
// calculate corners for the first quadrant only (delta.x and delta.y > 0 )
|
|
|
|
// currently, delta.x already is > 0.
|
|
|
|
// make delta.y > 0
|
|
|
|
bool change = delta.y < 0;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-25 07:43:50 +00:00
|
|
|
if( change )
|
2015-06-26 13:41:56 +00:00
|
|
|
delta.y = -delta.y;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-25 07:43:50 +00:00
|
|
|
// Now create the full polygon.
|
2011-10-17 20:01:27 +00:00
|
|
|
// Due to previous changes, the shape is always something like
|
2016-09-07 08:28:16 +00:00
|
|
|
// 3 4
|
|
|
|
// 2 5
|
2010-10-25 07:43:50 +00:00
|
|
|
// 1 6
|
|
|
|
wxPoint corner;
|
|
|
|
corner.x -= m_Size.x/2;
|
|
|
|
corner.y -= m_Size.y/2;
|
|
|
|
m_PolyCorners.push_back( corner ); // Lower left corner, start point (1)
|
|
|
|
corner.y += m_Size.y;
|
|
|
|
m_PolyCorners.push_back( corner ); // upper left corner, start point (2)
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-25 07:43:50 +00:00
|
|
|
if( delta.x || delta.y)
|
|
|
|
{
|
|
|
|
corner += delta;
|
|
|
|
m_PolyCorners.push_back( corner ); // upper left corner, end point (3)
|
|
|
|
}
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-25 07:43:50 +00:00
|
|
|
corner.x += m_Size.x;
|
|
|
|
m_PolyCorners.push_back( corner ); // upper right corner, end point (4)
|
|
|
|
corner.y -= m_Size.y;
|
|
|
|
m_PolyCorners.push_back( corner ); // lower right corner, end point (5)
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-25 07:43:50 +00:00
|
|
|
if( delta.x || delta.y )
|
|
|
|
{
|
|
|
|
corner -= delta;
|
|
|
|
m_PolyCorners.push_back( corner ); // lower left corner, start point (6)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create final polygon:
|
|
|
|
for( unsigned ii = 0; ii < m_PolyCorners.size(); ii++ )
|
|
|
|
{
|
|
|
|
if( change )
|
2015-06-26 13:41:56 +00:00
|
|
|
m_PolyCorners[ii].y = -m_PolyCorners[ii].y;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-25 07:43:50 +00:00
|
|
|
m_PolyCorners[ii] += start;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-28 14:42:05 +00:00
|
|
|
|
2011-03-29 19:33:07 +00:00
|
|
|
void GERBER_DRAW_ITEM::DrawGbrPoly( EDA_RECT* aClipBox,
|
2010-09-28 14:42:05 +00:00
|
|
|
wxDC* aDC,
|
2017-02-20 16:57:41 +00:00
|
|
|
COLOR4D aColor,
|
2010-09-28 14:42:05 +00:00
|
|
|
const wxPoint& aOffset,
|
2010-10-09 20:05:03 +00:00
|
|
|
bool aFilledShape )
|
2010-09-28 14:42:05 +00:00
|
|
|
{
|
|
|
|
std::vector<wxPoint> points;
|
|
|
|
|
|
|
|
points = m_PolyCorners;
|
2010-10-10 17:57:54 +00:00
|
|
|
for( unsigned ii = 0; ii < points.size(); ii++ )
|
2010-09-28 14:42:05 +00:00
|
|
|
{
|
2010-10-10 17:57:54 +00:00
|
|
|
points[ii] += aOffset;
|
|
|
|
points[ii] = GetABPosition( points[ii] );
|
2010-09-28 14:42:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GRClosedPoly( aClipBox, aDC, points.size(), &points[0], aFilledShape, aColor, aColor );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-01-12 17:32:24 +00:00
|
|
|
void GERBER_DRAW_ITEM::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList )
|
2010-09-28 14:42:05 +00:00
|
|
|
{
|
|
|
|
wxString msg;
|
2016-08-01 17:47:35 +00:00
|
|
|
wxString text;
|
2010-09-28 14:42:05 +00:00
|
|
|
|
|
|
|
msg = ShowGBRShape();
|
2013-01-12 17:32:24 +00:00
|
|
|
aList.push_back( MSG_PANEL_ITEM( _( "Type" ), msg, DARKCYAN ) );
|
2010-09-28 14:42:05 +00:00
|
|
|
|
2017-05-01 18:42:18 +00:00
|
|
|
// Display D_Code value with its attributes:
|
2016-08-01 17:47:35 +00:00
|
|
|
msg.Printf( _( "D Code %d" ), m_DCode );
|
|
|
|
D_CODE* apertDescr = GetDcodeDescr();
|
|
|
|
|
|
|
|
if( apertDescr->m_AperFunction.IsEmpty() )
|
|
|
|
text = _( "No attribute" );
|
|
|
|
else
|
|
|
|
text = apertDescr->m_AperFunction;
|
|
|
|
|
|
|
|
aList.push_back( MSG_PANEL_ITEM( msg, text, RED ) );
|
2010-10-10 17:57:54 +00:00
|
|
|
|
2017-05-01 18:42:18 +00:00
|
|
|
// Display graphic layer name
|
2016-09-07 08:28:16 +00:00
|
|
|
msg = GERBER_FILE_IMAGE_LIST::GetImagesList().GetDisplayName( GetLayer(), true );
|
2017-05-01 18:42:18 +00:00
|
|
|
aList.push_back( MSG_PANEL_ITEM( _( "Graphic Layer" ), msg, DARKGREEN ) );
|
2010-10-10 17:57:54 +00:00
|
|
|
|
2010-10-17 16:42:06 +00:00
|
|
|
// Display item rotation
|
|
|
|
// The full rotation is Image rotation + m_lyrRotation
|
|
|
|
// but m_lyrRotation is specific to this object
|
|
|
|
// so we display only this parameter
|
|
|
|
msg.Printf( wxT( "%f" ), m_lyrRotation );
|
2013-01-12 17:32:24 +00:00
|
|
|
aList.push_back( MSG_PANEL_ITEM( _( "Rotation" ), msg, BLUE ) );
|
2010-10-10 17:57:54 +00:00
|
|
|
|
2010-10-17 16:42:06 +00:00
|
|
|
// Display item polarity (item specific)
|
|
|
|
msg = m_LayerNegative ? _("Clear") : _("Dark");
|
2013-01-12 17:32:24 +00:00
|
|
|
aList.push_back( MSG_PANEL_ITEM( _( "Polarity" ), msg, BLUE ) );
|
2010-10-10 17:57:54 +00:00
|
|
|
|
2010-10-17 16:42:06 +00:00
|
|
|
// Display mirroring (item specific)
|
2010-10-16 14:51:22 +00:00
|
|
|
msg.Printf( wxT( "A:%s B:%s" ),
|
|
|
|
m_mirrorA ? _("Yes") : _("No"),
|
|
|
|
m_mirrorB ? _("Yes") : _("No"));
|
2013-01-12 17:32:24 +00:00
|
|
|
aList.push_back( MSG_PANEL_ITEM( _( "Mirror" ), msg, DARKRED ) );
|
2010-10-10 17:57:54 +00:00
|
|
|
|
2010-10-17 16:42:06 +00:00
|
|
|
// Display AB axis swap (item specific)
|
2010-10-16 14:51:22 +00:00
|
|
|
msg = m_swapAxis ? wxT( "A=Y B=X" ) : wxT( "A=X B=Y" );
|
2013-01-12 17:32:24 +00:00
|
|
|
aList.push_back( MSG_PANEL_ITEM( _( "AB axis" ), msg, DARKRED ) );
|
2016-07-27 13:27:19 +00:00
|
|
|
|
|
|
|
// Display net info, if exists
|
2016-08-16 10:56:20 +00:00
|
|
|
if( m_netAttributes.m_NetAttribType == GBR_NETLIST_METADATA::GBR_NETINFO_UNSPECIFIED )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Build full net info:
|
|
|
|
wxString net_msg;
|
|
|
|
wxString cmp_pad_msg;
|
|
|
|
|
|
|
|
if( ( m_netAttributes.m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_NET ) )
|
2016-07-27 13:27:19 +00:00
|
|
|
{
|
2016-08-16 10:56:20 +00:00
|
|
|
net_msg = _( "Net:" );
|
2016-10-23 17:43:31 +00:00
|
|
|
net_msg << " ";
|
2017-05-01 18:42:18 +00:00
|
|
|
|
2016-10-23 17:43:31 +00:00
|
|
|
if( m_netAttributes.m_Netname.IsEmpty() )
|
|
|
|
net_msg << "<no net name>";
|
|
|
|
else
|
|
|
|
net_msg << m_netAttributes.m_Netname;
|
2016-07-27 13:27:19 +00:00
|
|
|
}
|
2016-08-16 10:56:20 +00:00
|
|
|
|
|
|
|
if( ( m_netAttributes.m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_PAD ) )
|
|
|
|
{
|
|
|
|
cmp_pad_msg.Printf( _( "Cmp: %s; Pad: %s" ),
|
|
|
|
GetChars( m_netAttributes.m_Cmpref ),
|
|
|
|
GetChars( m_netAttributes.m_Padname ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
else if( ( m_netAttributes.m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_CMP ) )
|
|
|
|
{
|
|
|
|
cmp_pad_msg = _( "Cmp:" );
|
|
|
|
cmp_pad_msg << " " << m_netAttributes.m_Cmpref;
|
|
|
|
}
|
|
|
|
|
2017-05-01 18:42:18 +00:00
|
|
|
aList.push_back( MSG_PANEL_ITEM( net_msg, cmp_pad_msg, DARKCYAN ) );
|
2010-09-28 14:42:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-04 17:08:36 +00:00
|
|
|
bool GERBER_DRAW_ITEM::HitTest( const wxPoint& aRefPos ) const
|
2010-09-28 14:42:05 +00:00
|
|
|
{
|
2010-10-16 14:51:22 +00:00
|
|
|
// calculate aRefPos in XY gerber axis:
|
2010-10-10 17:57:54 +00:00
|
|
|
wxPoint ref_pos = GetXYPosition( aRefPos );
|
|
|
|
|
2011-10-17 20:01:27 +00:00
|
|
|
// TODO: a better analyze of the shape (perhaps create a D_CODE::HitTest for flashed items)
|
2012-09-22 11:19:37 +00:00
|
|
|
int radius = std::min( m_Size.x, m_Size.y ) >> 1;
|
2010-09-28 14:42:05 +00:00
|
|
|
|
|
|
|
if( m_Flashed )
|
2012-12-27 16:42:41 +00:00
|
|
|
return HitTestPoints( m_Start, ref_pos, radius );
|
2010-09-28 14:42:05 +00:00
|
|
|
else
|
2012-12-27 16:42:41 +00:00
|
|
|
return TestSegmentHit( ref_pos, m_Start, m_End, radius );
|
2010-09-28 14:42:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-04 17:08:36 +00:00
|
|
|
bool GERBER_DRAW_ITEM::HitTest( const EDA_RECT& aRefArea ) const
|
2010-09-28 14:42:05 +00:00
|
|
|
{
|
2010-10-10 17:57:54 +00:00
|
|
|
wxPoint pos = GetABPosition( m_Start );
|
2010-10-16 14:51:22 +00:00
|
|
|
|
2010-12-20 17:44:25 +00:00
|
|
|
if( aRefArea.Contains( pos ) )
|
2010-09-28 14:42:05 +00:00
|
|
|
return true;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-10-10 17:57:54 +00:00
|
|
|
pos = GetABPosition( m_End );
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-12-20 17:44:25 +00:00
|
|
|
if( aRefArea.Contains( pos ) )
|
2010-09-28 14:42:05 +00:00
|
|
|
return true;
|
2011-10-17 20:01:27 +00:00
|
|
|
|
2010-09-28 14:42:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(DEBUG)
|
|
|
|
|
2011-12-14 17:25:42 +00:00
|
|
|
void GERBER_DRAW_ITEM::Show( int nestLevel, std::ostream& os ) const
|
2010-09-28 14:42:05 +00:00
|
|
|
{
|
|
|
|
NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
|
|
|
|
|
|
|
|
" shape=\"" << m_Shape << '"' <<
|
|
|
|
" addr=\"" << std::hex << this << std::dec << '"' <<
|
2016-05-26 11:57:43 +00:00
|
|
|
" layer=\"" << GetLayer() << '"' <<
|
2010-09-28 14:42:05 +00:00
|
|
|
" size=\"" << m_Size << '"' <<
|
|
|
|
" flags=\"" << m_Flags << '"' <<
|
2013-03-30 19:55:26 +00:00
|
|
|
" status=\"" << GetStatus() << '"' <<
|
2010-09-28 14:42:05 +00:00
|
|
|
"<start" << m_Start << "/>" <<
|
|
|
|
"<end" << m_End << "/>";
|
|
|
|
|
|
|
|
os << "</" << GetClass().Lower().mb_str() << ">\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|