Finish implementation of DRAWSEGMENT::C_RECT.

It's currently only supported in the Footprint Editor.  It could be
easily added to the board editor (all the code is there), but the board
editor is a little short on room in the drawing tools toolbar.
This commit is contained in:
Jeff Young 2020-06-15 20:50:20 +01:00
parent 4480759599
commit aeed8e6e2c
31 changed files with 518 additions and 614 deletions

View File

@ -781,6 +781,31 @@ void BOARD_ADAPTER::AddShapeWithClearanceToContainer( const DRAWSEGMENT* aDrawSe
}
break;
case S_RECT:
{
std::vector<wxPoint> pts;
aDrawSegment->GetRectCorners( &pts );
const SFVEC2F topLeft3DU( pts[0].x * m_biuTo3Dunits, -pts[0].y * m_biuTo3Dunits );
const SFVEC2F topRight3DU( pts[1].x * m_biuTo3Dunits, -pts[1].y * m_biuTo3Dunits );
const SFVEC2F botRight3DU( pts[2].x * m_biuTo3Dunits, -pts[2].y * m_biuTo3Dunits );
const SFVEC2F botLeft3DU( pts[3].x * m_biuTo3Dunits, -pts[3].y * m_biuTo3Dunits );
aDstContainer->Add( new CROUNDSEGMENT2D( topLeft3DU, topRight3DU,
linewidth * m_biuTo3Dunits,
*aDrawSegment ) );
aDstContainer->Add( new CROUNDSEGMENT2D( topRight3DU, botRight3DU,
linewidth * m_biuTo3Dunits,
*aDrawSegment ) );
aDstContainer->Add( new CROUNDSEGMENT2D( botRight3DU, botLeft3DU,
linewidth * m_biuTo3Dunits,
*aDrawSegment ) );
aDstContainer->Add( new CROUNDSEGMENT2D( botLeft3DU, topLeft3DU,
linewidth * m_biuTo3Dunits,
*aDrawSegment ) );
}
break;
case S_ARC:
{
const unsigned int nr_segments =
@ -798,10 +823,10 @@ void BOARD_ADAPTER::AddShapeWithClearanceToContainer( const DRAWSEGMENT* aDrawSe
case S_SEGMENT:
{
const SFVEC2F start3DU( aDrawSegment->GetStart().x * m_biuTo3Dunits,
const SFVEC2F start3DU( aDrawSegment->GetStart().x * m_biuTo3Dunits,
-aDrawSegment->GetStart().y * m_biuTo3Dunits );
const SFVEC2F end3DU ( aDrawSegment->GetEnd().x * m_biuTo3Dunits,
const SFVEC2F end3DU ( aDrawSegment->GetEnd().x * m_biuTo3Dunits,
-aDrawSegment->GetEnd().y * m_biuTo3Dunits );
if( Is_segment_a_circle( start3DU, end3DU ) )
@ -812,8 +837,7 @@ void BOARD_ADAPTER::AddShapeWithClearanceToContainer( const DRAWSEGMENT* aDrawSe
}
else
{
aDstContainer->Add( new CROUNDSEGMENT2D( start3DU,
end3DU,
aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU,
linewidth * m_biuTo3Dunits,
*aDrawSegment ) );
}
@ -832,8 +856,8 @@ void BOARD_ADAPTER::AddShapeWithClearanceToContainer( const DRAWSEGMENT* aDrawSe
if( polyList.IsEmpty() ) // Just for caution
break;
Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer,
m_biuTo3Dunits, *aDrawSegment );
Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits,
*aDrawSegment );
}
break;

View File

@ -656,6 +656,7 @@ void EDA_RECT::Merge( const wxPoint& aPoint )
{
m_Pos = aPoint;
m_Size = wxSize( 0, 0 );
m_init = true;
return;
}

View File

@ -106,6 +106,7 @@ fp_circle
fp_curve
fp_line
fp_poly
fp_rect
fp_text
full
general
@ -115,6 +116,7 @@ gr_circle
gr_curve
gr_line
gr_poly
gr_rect
gr_text
hatch
hatch_thickness

View File

@ -30,7 +30,6 @@
#include <pcbnew.h>
#include <pcb_edit_frame.h>
#include <gr_basic.h>
#include <macros.h>
#include <msgpanel.h>
#include <class_board.h>
#include <class_module.h>
@ -43,7 +42,6 @@
#include <widgets/progress_reporter.h>
#include "ar_autoplacer.h"
#include "ar_cell.h"
#include "ar_matrix.h"
#include <memory>
@ -53,6 +51,15 @@
#define STEP_AR_MM 1.0
/* Bits characterizing cell */
#define CELL_IS_EMPTY 0x00
#define CELL_IS_HOLE 0x01 /* a conducting hole or obstacle */
#define CELL_IS_MODULE 0x02 /* auto placement occupied by a module */
#define CELL_IS_EDGE 0x20 /* Area and auto-placement: limiting cell contour (Board, Zone) */
#define CELL_IS_FRIEND 0x40 /* Area and auto-placement: cell part of the net */
#define CELL_IS_ZONE 0x80 /* Area and auto-placement: cell available */
/* Penalty (cost) for CntRot90 and CntRot180:
* CntRot90 and CntRot180 are from 0 (rotation allowed) to 10 (rotation not allowed)
*/
@ -265,7 +272,6 @@ bool AR_AUTOPLACER::fillMatrix()
}
void AR_AUTOPLACER::rotateModule( MODULE* module, double angle, bool incremental )
{
if( module == NULL )
@ -485,22 +491,6 @@ int AR_AUTOPLACER::testRectangle( const EDA_RECT& aRect, int side )
return AR_FREE_CELL;
}
int AR_AUTOPLACER::testModuleByPolygon( MODULE* aModule, int aSide, const wxPoint& aOffset )
{
// Test for footprint out of board:
// If a footprint is not fully inside the board, substract board polygon
// to the footprint polygon gives a non null area.
SHAPE_POLY_SET fp_area = m_fpAreaTop;
fp_area.Move( -aOffset );
SHAPE_POLY_SET out_of_board_area;
out_of_board_area.BooleanSubtract( fp_area, m_topFreeArea, SHAPE_POLY_SET::PM_FAST );
if( out_of_board_area.OutlineCount() )
return AR_OCCUIPED_BY_MODULE;
return AR_FREE_CELL;
}
/* Calculates and returns the clearance area of the rectangular surface
* aRect):

View File

@ -29,7 +29,6 @@
#ifndef __AR_AUTOPLACER_H
#define __AR_AUTOPLACER_H
#include "ar_cell.h"
#include "ar_matrix.h"
#include <class_board.h>
@ -63,13 +62,6 @@ public:
AR_RESULT AutoplaceModules( std::vector<MODULE*> aModules, BOARD_COMMIT* aCommit,
bool aPlaceOffboardModules = false );
const std::vector<MODULE*> QueryOffboardModules();
void SetPlacementGrid( int aGrid )
{
m_gridSize = aGrid;
}
/**
* Set a VIEW overlay to draw items during a autoplace session.
*/
@ -104,7 +96,6 @@ private:
void genModuleOnRoutingMatrix( MODULE* Module );
int testRectangle( const EDA_RECT& aRect, int side );
int testModuleByPolygon( MODULE* aModule,int aSide, const wxPoint& aOffset );
unsigned int calculateKeepOutArea( const EDA_RECT& aRect, int side );
int testModuleOnBoard( MODULE* aModule, bool TstOtherSide, const wxPoint& aOffset );
int getOptimalModulePlacement( MODULE* aModule );
@ -140,7 +131,6 @@ private:
BOARD* m_board;
wxPoint m_curPosition;
wxPoint m_moduleOffset;
double m_minCost;
int m_gridSize;

View File

@ -1,111 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
*
* Copyright (C) 1992-2012 KiCad Developers, see change_log.txt for contributors.
*
* First copyright (C) Randy Nevin, 1989 (see PCBCA package)
*
* 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
*/
#ifndef _AR_CELL_H_
#define _AR_CELL_H_
/* Bits characterizing cell */
#define CELL_IS_EMPTY 0x00
#define CELL_IS_HOLE 0x01 /* a conducting hole or obstacle */
#define CELL_IS_MODULE 0x02 /* auto placement occupied by a module */
#define CELL_IS_EDGE 0x20 /* Area and auto-placement: limiting cell contour (Board, Zone) */
#define CELL_IS_FRIEND 0x40 /* Area and auto-placement: cell part of the net */
#define CELL_IS_ZONE 0x80 /* Area and auto-placement: cell available */
/* Bit masks for presence of obstacles to autorouting */
#define OCCUPE 1 /* Autorouting: obstacle tracks and vias. */
#define VIA_IMPOSSIBLE 2 /* Autorouting: obstacle for vias. */
#define CURRENT_PAD 4
/* traces radiating outward from a hole to a side or corner */
#define HOLE_NORTH 0x00000002L /* upward */
#define HOLE_NORTHEAST 0x00000004L /* upward and right */
#define HOLE_EAST 0x00000008L /* to the right */
#define HOLE_SOUTHEAST 0x00000010L /* downward and right */
#define HOLE_SOUTH 0x00000020L /* downward */
#define HOLE_SOUTHWEST 0x00000040L /* downward and left */
#define HOLE_WEST 0x00000080L /* to the left */
#define HOLE_NORTHWEST 0x00000100L /* upward and left */
/* straight lines through the center */
#define LINE_HORIZONTAL 0x00000002L /* left-to-right line */
#define LINE_VERTICAL 0x00000004L /* top-to-bottom line */
/* lines cutting across a corner, connecting adjacent sides */
#define CORNER_NORTHEAST 0x00000008L /* upper right corner */
#define CORNER_SOUTHEAST 0x00000010L /* lower right corner */
#define CORNER_SOUTHWEST 0x00000020L /* lower left corner */
#define CORNER_NORTHWEST 0x00000040L /* upper left corner */
/* diagonal lines through the center */
#define DIAG_NEtoSW 0x00000080L /* northeast to southwest */
#define DIAG_SEtoNW 0x00000100L /* southeast to northwest */
/* 135 degree angle side-to-far-corner lines */
#define BENT_NtoSE 0x00000200L /* north to southeast */
#define BENT_NtoSW 0x00000400L /* north to southwest */
#define BENT_EtoSW 0x00000800L /* east to southwest */
#define BENT_EtoNW 0x00001000L /* east to northwest */
#define BENT_StoNW 0x00002000L /* south to northwest */
#define BENT_StoNE 0x00004000L /* south to northeast */
#define BENT_WtoNE 0x00008000L /* west to northeast */
#define BENT_WtoSE 0x00010000L /* west to southeast */
/* 90 degree corner-to-adjacent-corner lines */
#define ANGLE_NEtoSE 0x00020000L /* northeast to southeast */
#define ANGLE_SEtoSW 0x00040000L /* southeast to southwest */
#define ANGLE_SWtoNW 0x00080000L /* southwest to northwest */
#define ANGLE_NWtoNE 0x00100000L /* northwest to northeast */
/* 45 degree angle side-to-near-corner lines */
#define SHARP_NtoNE 0x00200000L /* north to northeast */
#define SHARP_EtoNE 0x00400000L /* east to northeast */
#define SHARP_EtoSE 0x00800000L /* east to southeast */
#define SHARP_StoSE 0x01000000L /* south to southeast */
#define SHARP_StoSW 0x02000000L /* south to southwest */
#define SHARP_WtoSW 0x04000000L /* west to southwest */
#define SHARP_WtoNW 0x08000000L /* west to northwest */
#define SHARP_NtoNW 0x10000000L /* north to northwest */
/* directions the cell can be reached from (point to previous cell) */
#define FROM_NOWHERE 0
#define FROM_NORTH 1
#define FROM_NORTHEAST 2
#define FROM_EAST 3
#define FROM_SOUTHEAST 4
#define FROM_SOUTH 5
#define FROM_SOUTHWEST 6
#define FROM_WEST 7
#define FROM_NORTHWEST 8
#define FROM_OTHERSIDE 9
#endif // __AR_CELL_H

View File

@ -26,16 +26,12 @@
*/
#include "ar_matrix.h"
#include "ar_cell.h"
#include <common.h>
#include <math/util.h> // for KiROUND
#include <math_for_graphics.h>
#include <trigo.h>
#include <class_drawsegment.h>
#include <class_pad.h>
#include <class_track.h>
AR_MATRIX::AR_MATRIX()
{
@ -46,7 +42,6 @@ AR_MATRIX::AR_MATRIX()
m_DirSide[0] = nullptr;
m_DirSide[1] = nullptr;
m_opWriteCell = nullptr;
m_InitMatrixDone = false;
m_Nrows = 0;
m_Ncols = 0;
m_MemSize = 0;
@ -100,8 +95,6 @@ int AR_MATRIX::InitRoutingMatrix()
if( m_Nrows <= 0 || m_Ncols <= 0 )
return 0;
m_InitMatrixDone = true; // we have been called
// give a small margin for memory allocation:
int ii = ( m_Nrows + 1 ) * ( m_Ncols + 1 );
@ -147,8 +140,6 @@ void AR_MATRIX::UnInitRoutingMatrix()
{
int ii;
m_InitMatrixDone = false;
for( ii = 0; ii < AR_MAX_ROUTING_LAYERS_COUNT; ii++ )
{
// de-allocate Dir matrix
@ -182,14 +173,10 @@ void AR_MATRIX::SetCellOperation( AR_MATRIX::CELL_OP aLogicOp )
switch( aLogicOp )
{
default:
case WRITE_CELL: m_opWriteCell = &AR_MATRIX::SetCell; break;
case WRITE_OR_CELL: m_opWriteCell = &AR_MATRIX::OrCell; break;
case WRITE_CELL: m_opWriteCell = &AR_MATRIX::SetCell; break;
case WRITE_OR_CELL: m_opWriteCell = &AR_MATRIX::OrCell; break;
case WRITE_XOR_CELL: m_opWriteCell = &AR_MATRIX::XorCell; break;
case WRITE_AND_CELL: m_opWriteCell = &AR_MATRIX::AndCell; break;
case WRITE_ADD_CELL: m_opWriteCell = &AR_MATRIX::AddCell; break;
}
}
@ -281,116 +268,6 @@ void AR_MATRIX::SetDist( int aRow, int aCol, int aSide, DIST_CELL x )
}
// fetch direction cell
int AR_MATRIX::GetDir( int aRow, int aCol, int aSide )
{
DIR_CELL* p;
p = m_DirSide[aSide];
return (int) ( p[aRow * m_Ncols + aCol] );
}
// store direction cell
void AR_MATRIX::SetDir( int aRow, int aCol, int aSide, int x )
{
DIR_CELL* p;
p = m_DirSide[aSide];
p[aRow * m_Ncols + aCol] = (char) x;
}
/* The tables of distances and keep out areas are established on the basis of a
* 50 units grid size (the pitch between the cells is 50 units).
* The actual distance could be computed by a scaling factor, but this is
* not needed, we can use only reduced values
*/
/* calculate approximate distance (manhattan distance)
*/
int AR_MATRIX::GetApxDist( int r1, int c1, int r2, int c2 )
{
int d1, d2; /* row and column deltas */
if( ( d1 = r1 - r2 ) < 0 ) /* get absolute row delta */
d1 = -d1;
if( ( d2 = c1 - c2 ) < 0 ) /* get absolute column delta */
d2 = -d2;
return ( d1 + d2 ) * 50;
}
/* distance to go thru a cell (en mils) */
static const int dist[10][10] = { /* OT=Otherside, OR=Origin (source) cell */
/*..........N, NE, E, SE, S, SW, W, NW, OT, OR */
/* N */ { 50, 60, 35, 60, 99, 60, 35, 60, 12, 12 },
/* NE */ { 60, 71, 60, 71, 60, 99, 60, 71, 23, 23 },
/* E */ { 35, 60, 50, 60, 35, 60, 99, 60, 12, 12 },
/* SE */ { 60, 71, 60, 71, 60, 71, 60, 99, 23, 23 },
/* S */ { 99, 60, 35, 60, 50, 60, 35, 60, 12, 12 },
/* SW */ { 60, 99, 60, 71, 60, 71, 60, 71, 23, 23 },
/* W */ { 35, 60, 99, 60, 35, 60, 50, 60, 12, 12 },
/* NW */ { 60, 71, 60, 99, 60, 71, 60, 71, 23, 23 },
/* OT */ { 12, 23, 12, 23, 12, 23, 12, 23, 99, 99 },
/* OR */ { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99 }
};
/* penalty for extraneous holes and corners, scaled by sharpness of turn */
static const int penalty[10][10] = { /* OT=Otherside, OR=Origin (source) cell */
/*......... N, NE, E, SE, S, SW, W, NW, OT, OR */
/* N */ { 0, 5, 10, 15, 20, 15, 10, 5, 50, 0 },
/* NE */ { 5, 0, 5, 10, 15, 20, 15, 10, 50, 0 },
/* E */ { 10, 5, 0, 5, 10, 15, 20, 15, 50, 0 },
/* SE */ { 15, 10, 5, 0, 5, 10, 15, 20, 50, 0 },
/* S */ { 20, 15, 10, 5, 0, 5, 10, 15, 50, 0 },
/* SW */ { 15, 20, 15, 10, 5, 0, 5, 10, 50, 0 },
/* W */ { 10, 15, 20, 15, 10, 5, 0, 5, 50, 0 },
/* NW */ { 5, 10, 15, 20, 15, 10, 5, 0, 50, 0 },
/* OT */ { 50, 50, 50, 50, 50, 50, 50, 50, 100, 0 },
/* OR */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
/* penalty pour directions preferencielles */
#define PN 20
static const int dir_penalty_TOP[10][10] = {
/* OT=Otherside, OR=Origin (source) cell */
/*......... N, NE, E, SE, S, SW, W, NW, OT, OR */
/* N */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
/* NE */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
/* E */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
/* SE */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
/* S */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
/* SW */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
/* W */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
/* NW */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
/* OT */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 },
/* OR */ { PN, 0, 0, 0, PN, 0, 0, 0, 0, 0 }
};
static int dir_penalty_BOTTOM[10][10] = {
/* OT=Otherside, OR=Origin (source) cell */
/*......... N, NE, E, SE, S, SW, W, NW, OT, OR */
/* N */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
/* NE */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
/* E */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
/* SE */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
/* S */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
/* SW */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
/* W */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
/* NW */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
/* OT */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 },
/* OR */ { 0, 0, PN, 0, 0, 0, PN, 0, 0, 0 }
};
/*
** x is the direction to enter the cell of interest.
** y is the direction to exit the cell of interest.
@ -401,44 +278,6 @@ static int dir_penalty_BOTTOM[10][10] = {
*/
/* calculate distance (with penalty) of a trace through a cell
*/
int AR_MATRIX::CalcDist( int x, int y, int z, int side )
{
int adjust, ldist;
adjust = 0; /* set if hole is encountered */
if( x == CELL_IS_EMPTY )
x = 10;
if( y == CELL_IS_EMPTY )
{
y = 10;
}
else if( y == FROM_OTHERSIDE )
{
if( z == CELL_IS_EMPTY )
z = 10;
adjust = penalty[x - 1][z - 1];
}
ldist = dist[x - 1][y - 1] + penalty[x - 1][y - 1] + adjust;
if( m_RouteCount > 1 )
{
if( side == AR_SIDE_BOTTOM )
ldist += dir_penalty_TOP[x - 1][y - 1];
if( side == AR_SIDE_TOP )
ldist += dir_penalty_BOTTOM[x - 1][y - 1];
}
return ldist * 10;
}
#define OP_CELL( layer, dy, dx ) \
{ \
if( layer == UNDEFINED_LAYER ) \
@ -947,147 +786,6 @@ void AR_MATRIX::TraceFilledRectangle( int ux0, int uy0, int ux1, int uy1, LSET a
}
/* Draws a line, if layer = -1 on all layers
*/
void AR_MATRIX::tracePcbLine(
int x0, int y0, int x1, int y1, LAYER_NUM layer, int color, AR_MATRIX::CELL_OP op_logic )
{
int dx, dy, lim;
int cumul, inc, il, delta;
SetCellOperation( op_logic );
if( x0 == x1 ) // Vertical.
{
if( y1 < y0 )
std::swap( y0, y1 );
dy = y0 / m_GridRouting;
lim = y1 / m_GridRouting;
dx = x0 / m_GridRouting;
// Clipping limits of board.
if( ( dx < 0 ) || ( dx >= m_Ncols ) )
return;
if( dy < 0 )
dy = 0;
if( lim >= m_Nrows )
lim = m_Nrows - 1;
for( ; dy <= lim; dy++ )
{
OP_CELL( layer, dy, dx );
}
return;
}
if( y0 == y1 ) // Horizontal
{
if( x1 < x0 )
std::swap( x0, x1 );
dx = x0 / m_GridRouting;
lim = x1 / m_GridRouting;
dy = y0 / m_GridRouting;
// Clipping limits of board.
if( ( dy < 0 ) || ( dy >= m_Nrows ) )
return;
if( dx < 0 )
dx = 0;
if( lim >= m_Ncols )
lim = m_Ncols - 1;
for( ; dx <= lim; dx++ )
{
OP_CELL( layer, dy, dx );
}
return;
}
// Here is some perspective: using the algorithm LUCAS.
if( abs( x1 - x0 ) >= abs( y1 - y0 ) ) // segment slightly inclined/
{
if( x1 < x0 )
{
std::swap( x1, x0 );
std::swap( y1, y0 );
}
dx = x0 / m_GridRouting;
lim = x1 / m_GridRouting;
dy = y0 / m_GridRouting;
inc = 1;
if( y1 < y0 )
inc = -1;
il = lim - dx;
cumul = il / 2;
delta = abs( y1 - y0 ) / m_GridRouting;
for( ; dx <= lim; )
{
if( ( dx >= 0 ) && ( dy >= 0 ) && ( dx < m_Ncols ) && ( dy < m_Nrows ) )
{
OP_CELL( layer, dy, dx );
}
dx++;
cumul += delta;
if( cumul > il )
{
cumul -= il;
dy += inc;
}
}
}
else
{
if( y1 < y0 )
{
std::swap( x1, x0 );
std::swap( y1, y0 );
}
dy = y0 / m_GridRouting;
lim = y1 / m_GridRouting;
dx = x0 / m_GridRouting;
inc = 1;
if( x1 < x0 )
inc = -1;
il = lim - dy;
cumul = il / 2;
delta = abs( x1 - x0 ) / m_GridRouting;
for( ; dy <= lim; )
{
if( ( dx >= 0 ) && ( dy >= 0 ) && ( dx < m_Ncols ) && ( dy < m_Nrows ) )
{
OP_CELL( layer, dy, dx );
}
dy++;
cumul += delta;
if( cumul > il )
{
cumul -= il;
dx += inc;
}
}
}
}
void AR_MATRIX::TraceSegmentPcb(
DRAWSEGMENT* pt_segm, int color, int marge, AR_MATRIX::CELL_OP op_logic )
{
@ -1101,69 +799,24 @@ void AR_MATRIX::TraceSegmentPcb(
//printf("traceSegm %d %d %d %d\n", ux0, uy0, ux1, uy1);
LAYER_NUM layer = pt_segm->GetLayer();
//if( color == VIA_IMPOSSIBLE )
layer = UNDEFINED_LAYER;
LAYER_NUM layer = UNDEFINED_LAYER; // Draw on all layers
switch( pt_segm->GetShape() )
{
// The segment is here a straight line or a circle or an arc.:
case S_CIRCLE: traceCircle( ux0, uy0, ux1, uy1, half_width, layer, color, op_logic ); break;
case S_CIRCLE:
traceCircle( ux0, uy0, ux1, uy1, half_width, layer, color, op_logic );
break;
case S_ARC:
traceArc( ux0, uy0, ux1, uy1, pt_segm->GetAngle(), half_width, layer, color, op_logic );
break;
// The segment is here a line segment.
default: drawSegmentQcq( ux0, uy0, ux1, uy1, half_width, layer, color, op_logic ); break;
}
}
void AR_MATRIX::TraceSegmentPcb( TRACK* aTrack, int color, int marge, AR_MATRIX::CELL_OP op_logic )
{
int half_width = ( aTrack->GetWidth() / 2 ) + marge;
// Test if VIA (filled circle need to be drawn)
if( aTrack->Type() == PCB_VIA_T )
{
LSET layer_mask;
if( aTrack->IsOnLayer( m_routeLayerBottom ) )
layer_mask.set( m_routeLayerBottom );
if( aTrack->IsOnLayer( m_routeLayerTop ) )
{
if( !layer_mask.any() )
layer_mask = LSET( m_routeLayerTop );
else
layer_mask.set();
}
if( color == VIA_IMPOSSIBLE )
layer_mask.set();
if( layer_mask.any() )
traceFilledCircle( aTrack->GetStart().x, aTrack->GetStart().y, half_width, layer_mask,
color, op_logic );
}
else
{
// Calculate the bounding rectangle of the segment
int ux0 = aTrack->GetStart().x - GetBrdCoordOrigin().x;
int uy0 = aTrack->GetStart().y - GetBrdCoordOrigin().y;
int ux1 = aTrack->GetEnd().x - GetBrdCoordOrigin().x;
int uy1 = aTrack->GetEnd().y - GetBrdCoordOrigin().y;
// Ordinary track
PCB_LAYER_ID layer = aTrack->GetLayer();
if( color == VIA_IMPOSSIBLE )
layer = UNDEFINED_LAYER;
case S_SEGMENT:
drawSegmentQcq( ux0, uy0, ux1, uy1, half_width, layer, color, op_logic );
break;
default:
break;
}
}

View File

@ -58,7 +58,6 @@ public:
// distance to cells
DIR_CELL* m_DirSide[AR_MAX_ROUTING_LAYERS_COUNT]; // the image map of 2 board sides:
// pointers back to source
bool m_InitMatrixDone;
int m_RoutingLayersCount; // Number of layers for autorouting (0 or 1)
int m_GridRouting; // Size of grid for autoplace/autoroute
EDA_RECT m_BrdBox; // Actual board bounding box
@ -133,18 +132,8 @@ public:
void AddCell( int aRow, int aCol, int aSide, MATRIX_CELL aCell );
DIST_CELL GetDist( int aRow, int aCol, int aSide );
void SetDist( int aRow, int aCol, int aSide, DIST_CELL );
int GetDir( int aRow, int aCol, int aSide );
void SetDir( int aRow, int aCol, int aSide, int aDir );
// calculate distance (with penalty) of a trace through a cell
int CalcDist( int x, int y, int z, int side );
// calculate approximate distance (manhattan distance)
int GetApxDist( int r1, int c1, int r2, int c2 );
void TraceSegmentPcb( DRAWSEGMENT* pt_segm, int color, int marge, AR_MATRIX::CELL_OP op_logic );
void TraceSegmentPcb( TRACK* aTrack, int color, int marge, AR_MATRIX::CELL_OP op_logic );
void CreateKeepOutRectangle(
int ux0, int uy0, int ux1, int uy1, int marge, int aKeepOut, LSET aLayerMask );
void PlacePad( D_PAD* aPad, int color, int marge, AR_MATRIX::CELL_OP op_logic );
@ -154,7 +143,6 @@ public:
AR_MATRIX::CELL_OP op_logic );
private:
void drawSegmentQcq( int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer, int color,
CELL_OP op_logic );
@ -164,8 +152,6 @@ private:
int cx, int cy, int radius, LSET aLayerMask, int color, AR_MATRIX::CELL_OP op_logic );
void traceArc( int ux0, int uy0, int ux1, int uy1, double ArcAngle, int lg, LAYER_NUM layer,
int color, AR_MATRIX::CELL_OP op_logic );
void tracePcbLine( int x0, int y0, int x1, int y1, LAYER_NUM layer, int color,
AR_MATRIX::CELL_OP op_logic );
};
#endif

View File

@ -368,6 +368,18 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerB
TransformRingToPolygon( aCornerBuffer, GetCenter(), GetRadius(), aError, width );
break;
case S_RECT:
{
std::vector<wxPoint> pts;
GetRectCorners( &pts );
aCornerBuffer.NewOutline();
for( const wxPoint& pt : pts )
aCornerBuffer.Append( pt );
}
break;
case S_ARC:
TransformArcToPolygon( aCornerBuffer, GetCenter(), GetArcStart(), m_Angle, aError, width );
break;

View File

@ -25,7 +25,6 @@
*/
#include <fctsys.h>
#include <macros.h>
#include <gr_basic.h>
#include <bezier_curves.h>
#include <pcb_screen.h>
@ -87,9 +86,14 @@ double DRAWSEGMENT::GetLength() const
break;
default:
case S_SEGMENT:
length = GetLineLength( GetStart(), GetEnd() );
break;
default:
wxASSERT_MSG( false, "DRAWSEGMENT::GetLength not implemented for shape"
+ ShowShape( GetShape() ) );
break;
}
return length;
@ -116,10 +120,8 @@ void DRAWSEGMENT::Move( const wxPoint& aMoveVector )
m_BezierC1 += aMoveVector;
m_BezierC2 += aMoveVector;
for( unsigned int ii = 0; ii < m_BezierPoints.size(); ii++ )
{
m_BezierPoints[ii] += aMoveVector;
}
for( wxPoint& pt : m_BezierPoints)
pt += aMoveVector;
break;
@ -136,6 +138,7 @@ void DRAWSEGMENT::Rotate( const wxPoint& aRotCentre, double aAngle )
case S_ARC:
case S_SEGMENT:
case S_CIRCLE:
case S_RECT:
// these can all be done by just rotating the start and end points
RotatePoint( &m_Start, aRotCentre, aAngle);
RotatePoint( &m_End, aRotCentre, aAngle);
@ -151,13 +154,11 @@ void DRAWSEGMENT::Rotate( const wxPoint& aRotCentre, double aAngle )
RotatePoint( &m_BezierC1, aRotCentre, aAngle);
RotatePoint( &m_BezierC2, aRotCentre, aAngle);
for( unsigned int ii = 0; ii < m_BezierPoints.size(); ii++ )
{
RotatePoint( &m_BezierPoints[ii], aRotCentre, aAngle);
}
for( wxPoint& pt : m_BezierPoints )
RotatePoint( &pt, aRotCentre, aAngle);
break;
case S_RECT:
default:
// un-handled edge transform
wxASSERT_MSG( false, wxT( "DRAWSEGMENT::Rotate not implemented for "
@ -385,7 +386,17 @@ void DRAWSEGMENT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL
aList.emplace_back( _( "Points" ), msg, DARKGREEN );
break;
default:
case S_RECT:
aList.emplace_back( shape, _( "Rectangle" ), RED );
msg = MessageTextFromValue( units, std::abs( m_End.x - m_Start.x ) );
aList.emplace_back( _( "Width" ), msg, DARKGREEN );
msg = MessageTextFromValue( units, std::abs( m_End.y - m_Start.y ) );
aList.emplace_back( _( "Height" ), msg, DARKGREEN );
break;
case S_SEGMENT:
{
aList.emplace_back( shape, _( "Segment" ), RED );
@ -398,6 +409,11 @@ void DRAWSEGMENT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL
msg.Printf( wxT( "%.1f" ), deg );
aList.emplace_back( _( "Angle" ), msg, DARKGREEN );
}
break;
default:
aList.emplace_back( shape, _( "Unrecognized" ), RED );
break;
}
if( m_Shape == S_POLYGON )
@ -436,6 +452,18 @@ const EDA_RECT DRAWSEGMENT::GetBoundingBox() const
switch( m_Shape )
{
case S_RECT:
{
std::vector<wxPoint> pts;
GetRectCorners( &pts );
bbox = EDA_RECT(); // re-init for merging
for( wxPoint& pt : pts )
bbox.Merge( pt );
}
break;
case S_SEGMENT:
bbox.SetEnd( m_End );
break;
@ -452,9 +480,8 @@ const EDA_RECT DRAWSEGMENT::GetBoundingBox() const
if( m_Poly.IsEmpty() )
break;
{
wxPoint p_end;
MODULE* module = GetParentModule();
bool first = true;
bbox = EDA_RECT(); // re-init for merging
for( auto iter = m_Poly.CIterate(); iter; iter++ )
{
@ -466,31 +493,12 @@ const EDA_RECT DRAWSEGMENT::GetBoundingBox() const
pt += module->GetPosition();
}
if( first )
{
p_end = pt;
bbox.SetX( pt.x );
bbox.SetY( pt.y );
first = false;
}
else
{
bbox.SetX( std::min( bbox.GetX(), pt.x ) );
bbox.SetY( std::min( bbox.GetY(), pt.y ) );
p_end.x = std::max( p_end.x, pt.x );
p_end.y = std::max( p_end.y, pt.y );
}
bbox.Merge( pt );
}
bbox.SetEnd( p_end );
}
break;
}
case S_CURVE:
bbox.Merge( m_BezierC1 );
bbox.Merge( m_BezierC2 );
bbox.Merge( m_End );
@ -572,6 +580,21 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition, int aAccuracy ) const
return true;
break;
case S_RECT:
{
std::vector<wxPoint> pts;
GetRectCorners( &pts );
if( TestSegmentHit( aPosition, pts[0], pts[1], maxdist )
|| TestSegmentHit( aPosition, pts[1], pts[2], maxdist )
|| TestSegmentHit( aPosition, pts[2], pts[3], maxdist )
|| TestSegmentHit( aPosition, pts[3], pts[0], maxdist ) )
{
return true;
}
}
break;
case S_POLYGON:
{
if( !IsPolygonFilled() )
@ -644,6 +667,26 @@ bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy
}
break;
case S_RECT:
if( aContained )
{
return arect.Contains( bb );
}
else
{
std::vector<wxPoint> pts;
GetRectCorners( &pts );
// Account for the width of the lines
arect.Inflate( GetWidth() / 2 );
return ( arect.Intersects( pts[0], pts[1] )
|| arect.Intersects( pts[1], pts[2] )
|| arect.Intersects( pts[2], pts[3] )
|| arect.Intersects( pts[3], pts[0] ) );
}
break;
case S_SEGMENT:
if( aContained )
{
@ -734,9 +777,8 @@ bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy
wxString DRAWSEGMENT::GetSelectMenuText( EDA_UNITS aUnits ) const
{
return wxString::Format( _( "Pcb Graphic %s, length %s on %s" ),
return wxString::Format( _( "Pcb Graphic %s on %s" ),
ShowShape( m_Shape ),
MessageTextFromValue( aUnits, GetLength() ),
GetLayerName() );
}
@ -769,6 +811,40 @@ const BOX2I DRAWSEGMENT::ViewBBox() const
}
void DRAWSEGMENT::GetRectCorners( std::vector<wxPoint>* pts ) const
{
MODULE* module = GetParentModule();
wxPoint topLeft = GetStart();
wxPoint botRight = GetEnd();
// Un-rotate rect topLeft and botRight
if( module && KiROUND( module->GetOrientation() ) % 900 != 0 )
{
topLeft -= module->GetPosition();
RotatePoint( &topLeft, -module->GetOrientation() );
botRight -= module->GetPosition();
RotatePoint( &botRight, -module->GetOrientation() );
}
// Set up the un-rotated 4 corners
pts->emplace_back( topLeft );
pts->emplace_back( botRight.x, topLeft.y );
pts->emplace_back( botRight );
pts->emplace_back( topLeft.x, botRight.y );
// Now re-rotate the 4 corners to get a diamond
if( module && KiROUND( module->GetOrientation() ) % 900 != 0 )
{
for( wxPoint& pt : *pts )
{
RotatePoint( &pt,module->GetOrientation() );
pt += module->GetPosition();
}
}
}
void DRAWSEGMENT::computeArcBBox( EDA_RECT& aBBox ) const
{
// Do not include the center, which is not necessarily
@ -816,21 +892,10 @@ void DRAWSEGMENT::computeArcBBox( EDA_RECT& aBBox ) const
{
switch( quarter )
{
case 0:
aBBox.Merge( wxPoint( m_Start.x, m_Start.y + radius ) ); // down
break;
case 1:
aBBox.Merge( wxPoint( m_Start.x - radius, m_Start.y ) ); // left
break;
case 2:
aBBox.Merge( wxPoint( m_Start.x, m_Start.y - radius ) ); // up
break;
case 3:
aBBox.Merge( wxPoint( m_Start.x + radius, m_Start.y ) ); // right
break;
case 0: aBBox.Merge( wxPoint( m_Start.x, m_Start.y + radius ) ); break; // down
case 1: aBBox.Merge( wxPoint( m_Start.x - radius, m_Start.y ) ); break; // left
case 2: aBBox.Merge( wxPoint( m_Start.x, m_Start.y - radius ) ); break; // up
case 3: aBBox.Merge( wxPoint( m_Start.x + radius, m_Start.y ) ); break; // right
}
if( directionCW )
@ -849,10 +914,8 @@ void DRAWSEGMENT::SetPolyPoints( const std::vector<wxPoint>& aPoints )
m_Poly.RemoveAllContours();
m_Poly.NewOutline();
for ( auto p : aPoints )
{
for ( const wxPoint& p : aPoints )
m_Poly.Append( p.x, p.y );
}
}
@ -865,9 +928,7 @@ const std::vector<wxPoint> DRAWSEGMENT::BuildPolyPointsList() const
if( m_Poly.COutline( 0 ).PointCount() )
{
for ( auto iter = m_Poly.CIterate(); iter; iter++ )
{
rv.emplace_back( iter->x, iter->y );
}
}
}

View File

@ -150,6 +150,7 @@ public:
const wxPoint& GetArcStart() const { return m_End; }
const wxPoint GetArcEnd() const;
const wxPoint GetArcMid() const;
void GetRectCorners( std::vector<wxPoint>* pts ) const;
/**
* function GetArcAngleStart()
@ -181,6 +182,11 @@ public:
*/
void SetCenter( const wxPoint& aCenterPoint ) { m_Start = aCenterPoint; }
const wxPoint GetFocusPosition() const override
{
return GetCenter();
}
/**
* Function GetParentModule
* returns a pointer to the parent module, or NULL if DRAWSEGMENT does not

View File

@ -30,14 +30,10 @@
*/
#include <fctsys.h>
#include <gr_basic.h>
#include <trigo.h>
#include <pcb_screen.h>
#include <confirm.h>
#include <kicad_string.h>
#include <richio.h>
#include <macros.h>
#include <math_for_graphics.h>
#include <pcb_base_frame.h>
#include <msgpanel.h>
#include <base_units.h>
@ -46,15 +42,12 @@
#include <pgm_base.h>
#include <settings/color_settings.h>
#include <settings/settings_manager.h>
#include <pcb_edit_frame.h>
#include <class_board.h>
#include <class_module.h>
#include <class_edge_mod.h>
#include <view/view.h>
#include <cstdio>
EDGE_MODULE::EDGE_MODULE( MODULE* parent, STROKE_T aShape ) :
DRAWSEGMENT( parent, PCB_MODULE_EDGE_T )

View File

@ -207,6 +207,7 @@ bool ConvertOutlineToPolygon( std::vector<DRAWSEGMENT*>& aSegList, SHAPE_POLY_SE
switch( graphic->GetShape() )
{
case S_RECT:
case S_SEGMENT:
{
if( graphic->GetStart().x < xmin.x )
@ -326,6 +327,16 @@ bool ConvertOutlineToPolygon( std::vector<DRAWSEGMENT*>& aSegList, SHAPE_POLY_SE
{
TransformCircleToPolygon( aPolygons, graphic->GetCenter(), graphic->GetRadius(), aTolerance );
}
else if( graphic->GetShape() == S_RECT )
{
std::vector<wxPoint> pts;
graphic->GetRectCorners( &pts );
aPolygons.NewOutline();
for( const wxPoint& pt : pts )
aPolygons.Append( pt );
}
else if( graphic->GetShape() == S_POLYGON )
{
MODULE* module = graphic->GetParentModule(); // NULL for items not in footprints
@ -542,6 +553,14 @@ bool ConvertOutlineToPolygon( std::vector<DRAWSEGMENT*>& aSegList, SHAPE_POLY_SE
aPolygons.Append( nextPt, -1, hole );
}
}
else if( graphic->GetShape() == S_RECT )
{
std::vector<wxPoint> pts;
graphic->GetRectCorners( &pts );
for( const wxPoint& pt : pts )
aPolygons.Append( pt, -1, hole );
}
else
{
// Polygon start point. Arbitrarily chosen end of the

View File

@ -180,6 +180,10 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataToWindow()
m_sizerLeft->Show( false );
break;
case S_RECT:
SetTitle( _( "Rectangle Properties" ) );
break;
case S_SEGMENT:
if( m_item->GetStart().x == m_item->GetEnd().x )
m_flipStartEnd = m_item->GetStart().y > m_item->GetEnd().y;

View File

@ -941,6 +941,18 @@ void DRC::testCopperDrawItem( BOARD_COMMIT& aCommit, BOARD_ITEM* aItem )
itemShape.emplace_back( SEG( drawItem->GetStart(), drawItem->GetEnd() ) );
break;
case S_RECT:
{
std::vector<wxPoint> pts;
drawItem->GetRectCorners( &pts );
itemShape.emplace_back( SEG( pts[0], pts[1] ) );
itemShape.emplace_back( SEG( pts[1], pts[2] ) );
itemShape.emplace_back( SEG( pts[2], pts[3] ) );
itemShape.emplace_back( SEG( pts[3], pts[0] ) );
}
break;
case S_CIRCLE:
{
// SHAPE_CIRCLE has no ConvertToPolyline() method, so use a 360.0 SHAPE_ARC

View File

@ -1259,6 +1259,31 @@ static void FootprintWriteShape( FILE* aFile, MODULE* module, const wxString& aS
-PtEdge->m_End0.y / SCALE_FACTOR );
break;
case S_RECT:
{
fprintf( aFile, "LINE %g %g %g %g\n",
PtEdge->m_Start0.x / SCALE_FACTOR,
-PtEdge->m_Start0.y / SCALE_FACTOR,
PtEdge->m_End0.x / SCALE_FACTOR,
-PtEdge->m_Start0.y / SCALE_FACTOR );
fprintf( aFile, "LINE %g %g %g %g\n",
PtEdge->m_End0.x / SCALE_FACTOR,
-PtEdge->m_Start0.y / SCALE_FACTOR,
PtEdge->m_End0.x / SCALE_FACTOR,
-PtEdge->m_End0.y / SCALE_FACTOR );
fprintf( aFile, "LINE %g %g %g %g\n",
PtEdge->m_End0.x / SCALE_FACTOR,
-PtEdge->m_End0.y / SCALE_FACTOR,
PtEdge->m_Start0.x / SCALE_FACTOR,
-PtEdge->m_End0.y / SCALE_FACTOR );
fprintf( aFile, "LINE %g %g %g %g\n",
PtEdge->m_Start0.x / SCALE_FACTOR,
-PtEdge->m_End0.y / SCALE_FACTOR,
PtEdge->m_Start0.x / SCALE_FACTOR,
-PtEdge->m_Start0.y / SCALE_FACTOR );
}
break;
case S_CIRCLE:
{
int radius = KiROUND( GetLineLength( PtEdge->m_End0,

View File

@ -102,6 +102,30 @@ static void idf_export_outline( BOARD* aPcb, IDF3_BOARD& aIDFBoard )
}
break;
case S_RECT:
{
if( ( graphic->GetStart().x == graphic->GetEnd().x )
&& ( graphic->GetStart().y == graphic->GetEnd().y ) )
break;
double top = graphic->GetStart().y * scale + offY;
double left = graphic->GetStart().x * scale + offX;
double bottom = graphic->GetEnd().y * scale + offY;
double right = graphic->GetEnd().x * scale + offX;
IDF_POINT corners[4];
corners[0] = IDF_POINT( left, top );
corners[1] = IDF_POINT( right, top );
corners[2] = IDF_POINT( right, bottom );
corners[3] = IDF_POINT( left, bottom );
lines.push_back( new IDF_SEGMENT( corners[0], corners[1] ) );
lines.push_back( new IDF_SEGMENT( corners[1], corners[2] ) );
lines.push_back( new IDF_SEGMENT( corners[2], corners[3] ) );
lines.push_back( new IDF_SEGMENT( corners[3], corners[0] ) );
}
break;
case S_ARC:
{
if( ( graphic->GetCenter().x == graphic->GetArcStart().x )

View File

@ -750,9 +750,19 @@ static void export_vrml_drawsegment( MODEL_VRML& aModel, DRAWSEGMENT* drawseg )
export_vrml_polygon( aModel, layer, drawseg, 0.0, wxPoint( 0, 0 ) );
break;
default:
case S_SEGMENT:
export_vrml_line( aModel, layer, x, y, xf, yf, w );
break;
case S_RECT:
export_vrml_line( aModel, layer, x, y, xf, y, w );
export_vrml_line( aModel, layer, xf, y, xf, yf, w );
export_vrml_line( aModel, layer, xf, yf, x, yf, w );
export_vrml_line( aModel, layer, x, yf, x, y, w );
break;
default:
break;
}
}

View File

@ -23,7 +23,6 @@
*/
#include <fctsys.h>
#include <kicad_string.h>
#include <common.h>
#include <build_version.h> // LEGACY_BOARD_FILE_VERSION
#include <macros.h>
@ -39,7 +38,6 @@
#include <class_drawsegment.h>
#include <class_pcb_target.h>
#include <class_edge_mod.h>
#include <pcb_plot_params.h>
#include <zones.h>
#include <kicad_plugin.h>
#include <pcb_parser.h>
@ -888,6 +886,12 @@ void PCB_IO::format( DRAWSEGMENT* aSegment, int aNestLevel ) const
break;
case S_RECT: // Rectangle
m_out->Print( aNestLevel, "(gr_rect (start %s) (end %s)",
FormatInternalUnits( aSegment->GetStart() ).c_str(),
FormatInternalUnits( aSegment->GetEnd() ).c_str() );
break;
case S_CIRCLE: // Circle
m_out->Print( aNestLevel, "(gr_circle (center %s) (end %s)",
FormatInternalUnits( aSegment->GetStart() ).c_str(),
@ -961,6 +965,12 @@ void PCB_IO::format( EDGE_MODULE* aModuleDrawing, int aNestLevel ) const
FormatInternalUnits( aModuleDrawing->GetEnd0() ).c_str() );
break;
case S_RECT: // Rectangle
m_out->Print( aNestLevel, "(fp_rect (start %s) (end %s)",
FormatInternalUnits( aModuleDrawing->GetStart0() ).c_str(),
FormatInternalUnits( aModuleDrawing->GetEnd0() ).c_str() );
break;
case S_CIRCLE: // Circle
m_out->Print( aNestLevel, "(fp_circle (center %s) (end %s)",
FormatInternalUnits( aModuleDrawing->GetStart0() ).c_str(),

View File

@ -68,7 +68,8 @@ class TEXTE_PCB;
//#define SEXPR_BOARD_FILE_VERSION 20200104 // pad property for fabrication
//#define SEXPR_BOARD_FILE_VERSION 20200119 // arcs in tracks
//#define SEXPR_BOARD_FILE_VERSION 20200512 // page -> paper
#define SEXPR_BOARD_FILE_VERSION 20200518 // save hole_to_hole_min
//#define SEXPR_BOARD_FILE_VERSION 20200518 // save hole_to_hole_min
#define SEXPR_BOARD_FILE_VERSION 20200614 // Add support for fp_rects and gr_rects
#define CTL_STD_LAYER_NAMES (1 << 0) ///< Use English Standard layer names
#define CTL_OMIT_NETS (1 << 1) ///< Omit pads net names (useless in library)

View File

@ -915,8 +915,15 @@ void PCB_PAINTER::draw( const DRAWSEGMENT* aSegment, int aLayer )
break;
case S_RECT:
wxASSERT_MSG( false, "Not tested yet" );
m_gal->DrawRectangle( start, end );
{
std::vector<wxPoint> pts;
aSegment->GetRectCorners( &pts );
m_gal->DrawSegment( pts[0], pts[1], thickness );
m_gal->DrawSegment( pts[1], pts[2], thickness );
m_gal->DrawSegment( pts[2], pts[3], thickness );
m_gal->DrawSegment( pts[3], pts[0], thickness );
}
break;
case S_ARC:

View File

@ -582,6 +582,7 @@ BOARD* PCB_PARSER::parseBOARD_unchecked()
case T_gr_arc:
case T_gr_circle:
case T_gr_curve:
case T_gr_rect:
case T_gr_line:
case T_gr_poly:
m_board->Add( parseDRAWSEGMENT(), ADD_MODE::APPEND );
@ -1942,7 +1943,7 @@ void PCB_PARSER::parseNETCLASS()
DRAWSEGMENT* PCB_PARSER::parseDRAWSEGMENT( bool aAllowCirclesZeroWidth )
{
wxCHECK_MSG( CurTok() == T_gr_arc || CurTok() == T_gr_circle || CurTok() == T_gr_curve ||
CurTok() == T_gr_line || CurTok() == T_gr_poly, NULL,
CurTok() == T_gr_rect || CurTok() == T_gr_line || CurTok() == T_gr_poly, NULL,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DRAWSEGMENT." ) );
T token;
@ -2017,6 +2018,30 @@ DRAWSEGMENT* PCB_PARSER::parseDRAWSEGMENT( bool aAllowCirclesZeroWidth )
NeedRIGHT();
break;
case T_gr_rect:
segment->SetShape( S_RECT );
NeedLEFT();
token = NextTok();
if( token != T_start )
Expecting( T_start );
pt.x = parseBoardUnits( "X coordinate" );
pt.y = parseBoardUnits( "Y coordinate" );
segment->SetStart( pt );
NeedRIGHT();
NeedLEFT();
token = NextTok();
if( token != T_end )
Expecting( T_end );
pt.x = parseBoardUnits( "X coordinate" );
pt.y = parseBoardUnits( "Y coordinate" );
segment->SetEnd( pt );
NeedRIGHT();
break;
case T_gr_line:
// Default DRAWSEGMENT type is S_SEGMENT.
NeedLEFT();
@ -2061,7 +2086,7 @@ DRAWSEGMENT* PCB_PARSER::parseDRAWSEGMENT( bool aAllowCirclesZeroWidth )
break;
default:
Expecting( "gr_arc, gr_circle, gr_curve, gr_line, or gr_poly" );
Expecting( "gr_arc, gr_circle, gr_curve, gr_line, gr_poly, or gp_rect" );
}
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
@ -2107,7 +2132,9 @@ DRAWSEGMENT* PCB_PARSER::parseDRAWSEGMENT( bool aAllowCirclesZeroWidth )
// However in custom pad shapes, zero-line width is allowed for filled circles
if( segment->GetShape() != S_POLYGON && segment->GetWidth() == 0 &&
!( segment->GetShape() == S_CIRCLE && aAllowCirclesZeroWidth ) )
{
segment->SetWidth( Millimeter2iu( DEFAULT_LINE_WIDTH ) );
}
return segment.release();
}
@ -2588,6 +2615,7 @@ MODULE* PCB_PARSER::parseMODULE_unchecked( wxArrayString* aInitialComments )
case T_fp_circle:
case T_fp_curve:
case T_fp_rect:
case T_fp_line:
case T_fp_poly:
{
@ -2628,7 +2656,7 @@ MODULE* PCB_PARSER::parseMODULE_unchecked( wxArrayString* aInitialComments )
"autoplace_cost90, autoplace_cost180, solder_mask_margin, "
"solder_paste_margin, solder_paste_ratio, clearance, "
"zone_connect, thermal_width, thermal_gap, attr, fp_text, "
"fp_arc, fp_circle, fp_curve, fp_line, fp_poly, pad, "
"fp_arc, fp_circle, fp_curve, fp_line, fp_poly, fp_rect, pad, "
"zone, or model" );
}
}
@ -2738,7 +2766,7 @@ TEXTE_MODULE* PCB_PARSER::parseTEXTE_MODULE()
EDGE_MODULE* PCB_PARSER::parseEDGE_MODULE()
{
wxCHECK_MSG( CurTok() == T_fp_arc || CurTok() == T_fp_circle || CurTok() == T_fp_curve ||
CurTok() == T_fp_line || CurTok() == T_fp_poly, NULL,
CurTok() == T_fp_rect || CurTok() == T_fp_line || CurTok() == T_fp_poly, NULL,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDGE_MODULE." ) );
wxPoint pt;
@ -2821,6 +2849,31 @@ EDGE_MODULE* PCB_PARSER::parseEDGE_MODULE()
NeedRIGHT();
break;
case T_fp_rect:
segment->SetShape( S_RECT );
NeedLEFT();
token = NextTok();
if( token != T_start )
Expecting( T_start );
pt.x = parseBoardUnits( "X coordinate" );
pt.y = parseBoardUnits( "Y coordinate" );
segment->SetStart0( pt );
NeedRIGHT();
NeedLEFT();
token = NextTok();
if( token != T_end )
Expecting( T_end );
pt.x = parseBoardUnits( "X coordinate" );
pt.y = parseBoardUnits( "Y coordinate" );
segment->SetEnd0( pt );
NeedRIGHT();
break;
case T_fp_line:
// Default DRAWSEGMENT type is S_SEGMENT.
NeedLEFT();
@ -2865,7 +2918,7 @@ EDGE_MODULE* PCB_PARSER::parseEDGE_MODULE()
break;
default:
Expecting( "fp_arc, fp_circle, fp_curve, fp_line, or fp_poly" );
Expecting( "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, or fp_rect" );
}
for( token = NextTok(); token != T_RIGHT; token = NextTok() )

View File

@ -529,6 +529,18 @@ void BRDITEMS_PLOTTER::PlotFootprintGraphicItem( EDGE_MODULE* aEdge )
m_plotter->ThickSegment( pos, end, thickness, GetPlotMode(), &gbr_metadata );
break;
case S_RECT:
{
std::vector<wxPoint> pts;
aEdge->GetRectCorners( &pts );
m_plotter->ThickSegment( pts[0], pts[1], thickness, GetPlotMode(), &gbr_metadata );
m_plotter->ThickSegment( pts[1], pts[2], thickness, GetPlotMode(), &gbr_metadata );
m_plotter->ThickSegment( pts[2], pts[3], thickness, GetPlotMode(), &gbr_metadata );
m_plotter->ThickSegment( pts[3], pts[0], thickness, GetPlotMode(), &gbr_metadata );
}
break;
case S_CIRCLE:
radius = KiROUND( GetLineLength( end, pos ) );
m_plotter->ThickCircle( pos, radius * 2, thickness, GetPlotMode(), &gbr_metadata );

View File

@ -985,6 +985,18 @@ bool PNS_KICAD_IFACE_BASE::syncGraphicalItem( PNS::NODE* aWorld, DRAWSEGMENT* aI
break;
case S_RECT:
{
std::vector<wxPoint> pts;
aItem->GetRectCorners( &pts );
segs.push_back( new SHAPE_SEGMENT( pts[0], pts[1], aItem->GetWidth() ) );
segs.push_back( new SHAPE_SEGMENT( pts[1], pts[2], aItem->GetWidth() ) );
segs.push_back( new SHAPE_SEGMENT( pts[2], pts[3], aItem->GetWidth() ) );
segs.push_back( new SHAPE_SEGMENT( pts[3], pts[0], aItem->GetWidth() ) );
}
break;
case S_CIRCLE:
{
// SHAPE_CIRCLE has no ConvertToPolyline() method, so use a 360.0 SHAPE_ARC

View File

@ -145,22 +145,23 @@ void FOOTPRINT_EDIT_FRAME::ReCreateVToolbar()
m_drawToolBar = new ACTION_TOOLBAR( this, ID_V_TOOLBAR, wxDefaultPosition, wxDefaultSize,
KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL );
m_drawToolBar->Add( ACTIONS::selectionTool, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( ACTIONS::selectionTool, ACTION_TOOLBAR::TOGGLE );
KiScaledSeparator( m_drawToolBar, this );
m_drawToolBar->Add( PCB_ACTIONS::placePad, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::drawLine, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::drawCircle, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::drawArc, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::drawPolygon, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::placePad, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::drawLine, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::drawRectangle, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::drawCircle, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::drawArc, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::drawPolygon, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::drawZoneKeepout, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::placeText, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( ACTIONS::deleteTool, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::placeText, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( ACTIONS::deleteTool, ACTION_TOOLBAR::TOGGLE );
KiScaledSeparator( m_drawToolBar, this );
m_drawToolBar->Add( PCB_ACTIONS::setAnchor, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::gridSetOrigin, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( ACTIONS::measureTool, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::setAnchor, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( PCB_ACTIONS::gridSetOrigin, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( ACTIONS::measureTool, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Realize();
}
@ -237,8 +238,8 @@ void FOOTPRINT_EDIT_FRAME::SyncToolbars()
m_mainToolBar->Refresh();
m_optionsToolBar->Toggle( ACTIONS::toggleGrid, IsGridVisible() );
m_optionsToolBar->Toggle( ACTIONS::metricUnits, GetUserUnits() != EDA_UNITS::INCHES );
m_optionsToolBar->Toggle( ACTIONS::imperialUnits, GetUserUnits() == EDA_UNITS::INCHES );
m_optionsToolBar->Toggle( ACTIONS::metricUnits, GetUserUnits() != EDA_UNITS::INCHES );
m_optionsToolBar->Toggle( ACTIONS::imperialUnits, GetUserUnits() == EDA_UNITS::INCHES );
m_optionsToolBar->Toggle( ACTIONS::togglePolarCoords, GetShowPolarCoords() );
m_optionsToolBar->Toggle( PCB_ACTIONS::padDisplayMode, !opts.m_DisplayPadFill );
m_optionsToolBar->Toggle( PCB_ACTIONS::textOutlines, !opts.m_DisplayTextFill );
@ -252,6 +253,7 @@ void FOOTPRINT_EDIT_FRAME::SyncToolbars()
// If there is no footprint loaded, disable the editing tools
m_drawToolBar->Toggle( PCB_ACTIONS::placePad, false, false );
m_drawToolBar->Toggle( PCB_ACTIONS::drawLine, false, false );
m_drawToolBar->Toggle( PCB_ACTIONS::drawRectangle, false, false );
m_drawToolBar->Toggle( PCB_ACTIONS::drawCircle, false, false );
m_drawToolBar->Toggle( PCB_ACTIONS::drawArc, false, false );
m_drawToolBar->Toggle( PCB_ACTIONS::drawPolygon, false, false );
@ -266,6 +268,7 @@ void FOOTPRINT_EDIT_FRAME::SyncToolbars()
{
TOGGLE_TOOL( m_drawToolBar, PCB_ACTIONS::placePad );
TOGGLE_TOOL( m_drawToolBar, PCB_ACTIONS::drawLine );
TOGGLE_TOOL( m_drawToolBar, PCB_ACTIONS::drawRectangle );
TOGGLE_TOOL( m_drawToolBar, PCB_ACTIONS::drawCircle );
TOGGLE_TOOL( m_drawToolBar, PCB_ACTIONS::drawArc );
TOGGLE_TOOL( m_drawToolBar, PCB_ACTIONS::drawPolygon );

View File

@ -183,6 +183,48 @@ int DRAWING_TOOL::DrawLine( const TOOL_EVENT& aEvent )
}
int DRAWING_TOOL::DrawRectangle( const TOOL_EVENT& aEvent )
{
if( m_editModules && !m_frame->GetModel() )
return 0;
MODULE* module = dynamic_cast<MODULE*>( m_frame->GetModel() );
DRAWSEGMENT* rect = m_editModules ? new EDGE_MODULE( module ) : new DRAWSEGMENT;
BOARD_COMMIT commit( m_frame );
SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::RECT );
OPT<VECTOR2D> startingPoint = boost::make_optional<VECTOR2D>( false, VECTOR2D( 0, 0 ) );
rect->SetFlags(IS_NEW );
if( aEvent.HasPosition() )
startingPoint = getViewControls()->GetCursorPosition( !aEvent.Modifier( MD_ALT ) );
std::string tool = aEvent.GetCommandStr().get();
m_frame->PushTool( tool );
Activate();
while( drawSegment( tool, S_RECT, rect, startingPoint ) )
{
if( rect )
{
if( m_editModules )
static_cast<EDGE_MODULE*>( rect )->SetLocalCoord();
commit.Add( rect );
commit.Push( _( "Draw a rectangle" ) );
m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, rect );
}
rect = m_editModules ? new EDGE_MODULE( module ) : new DRAWSEGMENT;
rect->SetFlags(IS_NEW );
startingPoint = NULLOPT;
}
return 0;
}
int DRAWING_TOOL::DrawCircle( const TOOL_EVENT& aEvent )
{
if( m_editModules && !m_frame->GetModel() )
@ -918,8 +960,8 @@ int DRAWING_TOOL::SetAnchor( const TOOL_EVENT& aEvent )
bool DRAWING_TOOL::drawSegment( const std::string& aTool, int aShape, DRAWSEGMENT*& aGraphic,
OPT<VECTOR2D> aStartingPoint )
{
// Only two shapes are currently supported
assert( aShape == S_SEGMENT || aShape == S_CIRCLE );
// Only three shapes are currently supported
assert( aShape == S_SEGMENT || aShape == S_CIRCLE || aShape == S_RECT );
GRID_HELPER grid( m_toolMgr, m_frame->GetMagneticItemsSettings() );
POINT_EDITOR* pointEditor = m_toolMgr->GetTool<POINT_EDITOR>();
@ -1938,6 +1980,7 @@ void DRAWING_TOOL::setTransitions()
{
Go( &DRAWING_TOOL::DrawLine, PCB_ACTIONS::drawLine.MakeEvent() );
Go( &DRAWING_TOOL::DrawZone, PCB_ACTIONS::drawPolygon.MakeEvent() );
Go( &DRAWING_TOOL::DrawRectangle, PCB_ACTIONS::drawRectangle.MakeEvent() );
Go( &DRAWING_TOOL::DrawCircle, PCB_ACTIONS::drawCircle.MakeEvent() );
Go( &DRAWING_TOOL::DrawArc, PCB_ACTIONS::drawArc.MakeEvent() );
Go( &DRAWING_TOOL::DrawDimension, PCB_ACTIONS::drawDimension.MakeEvent() );

View File

@ -63,6 +63,7 @@ public:
{
NONE,
LINE,
RECT,
CIRCLE,
ARC,
TEXT,
@ -91,6 +92,14 @@ public:
*/
int DrawLine( const TOOL_EVENT& aEvent );
/**
* Function DrawRectangle()
* Starts interactively drawing a rectangle. After invoking the function it expects the user
* to first click on a point that is going to be used as the top-left of the rectangle. The
* second click determines the bottom-right.
*/
int DrawRectangle( const TOOL_EVENT& aEvent );
/**
* Function DrawCircle()
* Starts interactively drawing a circle. After invoking the function it expects the user

View File

@ -66,6 +66,11 @@ TOOL_ACTION PCB_ACTIONS::drawPolygon( "pcbnew.InteractiveDrawing.graphicPolygon"
_( "Draw Graphic Polygon" ), _( "Draw a graphic polygon" ),
add_graphical_polygon_xpm, AF_ACTIVATE, (void*) ZONE_MODE::GRAPHIC_POLYGON );
TOOL_ACTION PCB_ACTIONS::drawRectangle( "pcbnew.InteractiveDrawing.rectangle",
AS_GLOBAL, 0, "",
_( "Draw Rectangle" ), _( "Draw a rectangle" ),
add_rectangle_xpm, AF_ACTIVATE );
TOOL_ACTION PCB_ACTIONS::drawCircle( "pcbnew.InteractiveDrawing.circle",
AS_GLOBAL,
MD_SHIFT + MD_CTRL + 'C', LEGACY_HK_NAME( "Draw Circle" ),

View File

@ -136,6 +136,7 @@ public:
// Drawing Tool Activations
static TOOL_ACTION drawLine;
static TOOL_ACTION drawPolygon;
static TOOL_ACTION drawRectangle;
static TOOL_ACTION drawCircle;
static TOOL_ACTION drawArc;
static TOOL_ACTION placeText;

View File

@ -50,6 +50,11 @@ enum SEG_POINTS
SEG_START, SEG_END
};
enum RECT_POINTS
{
RECT_TOP_LEFT, RECT_TOP_RIGHT, RECT_BOT_RIGHT, RECT_BOT_LEFT
};
enum ARC_POINTS
{
ARC_CENTER, ARC_START, ARC_MID, ARC_END
@ -144,6 +149,13 @@ public:
points->AddPoint( segment->GetEnd() );
break;
case S_RECT:
points->AddPoint( segment->GetStart() );
points->AddPoint( wxPoint( segment->GetEnd().x, segment->GetStart().y ) );
points->AddPoint( segment->GetEnd() );
points->AddPoint( wxPoint( segment->GetStart().x, segment->GetEnd().y ) );
break;
case S_ARC:
points->AddPoint( segment->GetCenter() );
points->AddPoint( segment->GetArcStart() );
@ -163,7 +175,6 @@ public:
case S_CIRCLE:
points->AddPoint( segment->GetCenter() );
points->AddPoint( segment->GetEnd() );
break;
case S_POLYGON:
@ -441,6 +452,29 @@ void POINT_EDITOR::updateItem() const
break;
case S_RECT:
{
if( isModified( m_editPoints->Point( RECT_TOP_LEFT ) ) )
{
segment->SetStart( (wxPoint) m_editPoints->Point( RECT_TOP_LEFT ).GetPosition() );
}
else if( isModified( m_editPoints->Point( RECT_TOP_RIGHT ) ) )
{
segment->SetStartY( m_editPoints->Point( RECT_TOP_RIGHT ).GetPosition().y );
segment->SetEndX( m_editPoints->Point( RECT_TOP_RIGHT ).GetPosition().x );
}
else if( isModified( m_editPoints->Point( RECT_BOT_RIGHT ) ) )
{
segment->SetEnd( (wxPoint) m_editPoints->Point( RECT_BOT_RIGHT ).GetPosition() );
}
else if( isModified( m_editPoints->Point( RECT_BOT_LEFT ) ) )
{
segment->SetStartX( m_editPoints->Point( RECT_BOT_LEFT ).GetPosition().x );
segment->SetEndY( m_editPoints->Point( RECT_BOT_LEFT ).GetPosition().y );
}
}
break;
case S_ARC:
{
VECTOR2I center = m_editPoints->Point( ARC_CENTER ).GetPosition();
@ -482,9 +516,8 @@ void POINT_EDITOR::updateItem() const
segment->SetAngle( newAngle );
}
break;
}
break;
case S_CIRCLE:
{
@ -500,9 +533,8 @@ void POINT_EDITOR::updateItem() const
{
segment->SetEnd( wxPoint( end.x, end.y ) );
}
break;
}
break;
case S_POLYGON:
{
@ -512,8 +544,8 @@ void POINT_EDITOR::updateItem() const
outline.SetVertex( i, m_editPoints->Point( i ).GetPosition() );
validatePolygon( outline );
break;
}
break;
case S_CURVE:
if( isModified( m_editPoints->Point( BEZIER_CURVE_START ) ) )
@ -685,6 +717,15 @@ void POINT_EDITOR::updatePoints()
m_editPoints->Point( SEG_END ).SetPosition( segment->GetEnd() );
break;
case S_RECT:
m_editPoints->Point( RECT_TOP_LEFT ).SetPosition( segment->GetStart() );
m_editPoints->Point( RECT_TOP_RIGHT ).SetPosition( segment->GetEnd().x,
segment->GetStart().y );
m_editPoints->Point( RECT_BOT_RIGHT ).SetPosition( segment->GetEnd() );
m_editPoints->Point( RECT_BOT_LEFT ).SetPosition( segment->GetStart().x,
segment->GetEnd().y );
break;
case S_ARC:
m_editPoints->Point( ARC_CENTER ).SetPosition( segment->GetCenter() );
m_editPoints->Point( ARC_START ).SetPosition( segment->GetArcStart() );

View File

@ -480,6 +480,12 @@ public:
y = 0.0;
}
IDF_POINT( double aX, double aY )
{
x = aX;
y = aY;
}
/**
* Function Matches()
* returns true if the given coordinate point is within the given radius