DRAWSEGMENT, S_POLYGON shape: remove useless copies or conversion to std::vector<wxPoint> of SHPE_POLY_SET polygon shape.

Rename GetPolyPoint() to BuildPolyPointsList(), because GetPolyPoint() looks like an accessor, but it is not an accessor.
(Using it as accessor can creates a *very long calculation time* for very basic access to polygon vertices)

Fixes: lp:1745050
https://bugs.launchpad.net/kicad/+bug/1745050
This commit is contained in:
jean-pierre charras 2018-01-24 14:22:43 +01:00
parent c95c77c51a
commit 270a63daac
16 changed files with 162 additions and 99 deletions

View File

@ -520,7 +520,7 @@ void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnOKButtonClick( wxCommandEvent& event
SCH_REFERENCE_LIST components;
GetParent()->GetCurrentSheet().GetComponents( components );
for( int i = 0; i < components.GetCount(); i++ )
for( unsigned i = 0; i < components.GetCount(); i++ )
{
SCH_REFERENCE component = components[i];
if( component.GetLibPart()->GetLibId() == thisLibId

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
* Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wandadoo.fr
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.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
@ -331,6 +331,8 @@ public:
static std::string FormatInternalUnits( const wxPoint& aPoint );
static std::string FormatInternalUnits( const VECTOR2I& aPoint );
static std::string FormatInternalUnits( const wxSize& aSize );
virtual void ViewGetLayers( int aLayers[], int& aCount ) const override;

View File

@ -515,55 +515,54 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerB
break;
case S_POLYGON:
if ( GetPolyPoints().size() < 2 )
break; // Malformed polygon.
if( IsPolyShapeValid() )
{
// The polygon is expected to be a simple polygon
// not self intersecting, no hole.
MODULE* module = GetParentModule(); // NULL for items not in footprints
double orientation = module ? module->GetOrientation() : 0.0;
wxPoint offset;
// The polygon is expected to be a simple polygon
// not self intersecting, no hole.
MODULE* module = GetParentModule(); // NULL for items not in footprints
double orientation = module ? module->GetOrientation() : 0.0;
wxPoint offset;
if( module )
offset = module->GetPosition();
if( module )
offset = module->GetPosition();
// Build the polygon with the actual position and orientation:
std::vector< wxPoint> poly;
poly = GetPolyPoints();
for( unsigned ii = 0; ii < poly.size(); ii++ )
{
RotatePoint( &poly[ii], orientation );
poly[ii] += offset;
}
// Generate polygons for the outline + clearance
// This code is compatible with a polygon with holes linked to external outline
// by overlapping segments.
// Insert the initial polygon:
aCornerBuffer.NewOutline();
for( unsigned ii = 0; ii < poly.size(); ii++ )
aCornerBuffer.Append( poly[ii].x, poly[ii].y );
if( linewidth ) // Add thick outlines
{
CPolyPt corner1( poly[poly.size()-1] );
// Build the polygon with the actual position and orientation:
std::vector< wxPoint> poly;
poly = BuildPolyPointsList();
for( unsigned ii = 0; ii < poly.size(); ii++ )
{
CPolyPt corner2( poly[ii] );
if( corner2 != corner1 )
{
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
corner1, corner2, aCircleToSegmentsCount, linewidth );
}
corner1 = corner2;
RotatePoint( &poly[ii], orientation );
poly[ii] += offset;
}
// Generate polygons for the outline + clearance
// This code is compatible with a polygon with holes linked to external outline
// by overlapping segments.
// Insert the initial polygon:
aCornerBuffer.NewOutline();
for( unsigned ii = 0; ii < poly.size(); ii++ )
aCornerBuffer.Append( poly[ii].x, poly[ii].y );
if( linewidth ) // Add thick outlines
{
wxPoint corner1( poly[poly.size()-1] );
for( unsigned ii = 0; ii < poly.size(); ii++ )
{
wxPoint corner2( poly[ii] );
if( corner2 != corner1 )
{
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
corner1, corner2, aCircleToSegmentsCount, linewidth );
}
corner1 = corner2;
}
}
}
}
break;

View File

@ -184,6 +184,12 @@ std::string BOARD_ITEM::FormatInternalUnits( const wxPoint& aPoint )
}
std::string BOARD_ITEM::FormatInternalUnits( const VECTOR2I& aPoint )
{
return FormatInternalUnits( aPoint.x ) + " " + FormatInternalUnits( aPoint.y );
}
std::string BOARD_ITEM::FormatInternalUnits( const wxSize& aSize )
{
return FormatInternalUnits( aSize.GetWidth() ) + " " + FormatInternalUnits( aSize.GetHeight() );

View File

@ -806,7 +806,8 @@ void DRAWSEGMENT::SetPolyPoints( const std::vector<wxPoint>& aPoints )
}
}
const std::vector<wxPoint> DRAWSEGMENT::GetPolyPoints() const
const std::vector<wxPoint> DRAWSEGMENT::BuildPolyPointsList() const
{
std::vector<wxPoint> rv;
@ -824,6 +825,30 @@ const std::vector<wxPoint> DRAWSEGMENT::GetPolyPoints() const
return rv;
}
bool DRAWSEGMENT::IsPolyShapeValid() const
{
// return true if the polygonal shape is valid (has more than 2 points)
if( GetPolyShape().OutlineCount() == 0 )
return false;
const SHAPE_LINE_CHAIN& outline = ((SHAPE_POLY_SET&)GetPolyShape()).Outline( 0 );
return outline.PointCount() > 2;
}
int DRAWSEGMENT::GetPointCount() const
{
// return the number of corners of the polygonal shape
// this shape is expected to be only one polygon without hole
if( GetPolyShape().OutlineCount() )
return GetPolyShape().VertexCount( 0 );
return 0;
}
void DRAWSEGMENT::SwapData( BOARD_ITEM* aImage )
{
assert( aImage->Type() == PCB_LINE_T );

View File

@ -167,9 +167,26 @@ public:
// Accessors:
const std::vector<wxPoint>& GetBezierPoints() const { return m_BezierPoints; }
const std::vector<wxPoint> GetPolyPoints() const;
/** Build and return the list of corners in a std::vector<wxPoint>
* It must be used only to convert the SHAPE_POLY_SET internal corner buffer
* to a list of wxPoints, and nothing else, because it duplicates the buffer,
* that is inefficient to know for instance the corner count
*/
const std::vector<wxPoint> BuildPolyPointsList() const;
/** @return the number of corners of the polygonal shape
*/
int GetPointCount() const;
// Accessors to the polygonal shape
SHAPE_POLY_SET& GetPolyShape() { return m_Poly; }
const SHAPE_POLY_SET& GetPolyShape() const { return m_Poly; }
/**
* @return true if the polygonal shape is valid (has more than 2 points)
*/
bool IsPolyShapeValid() const;
void SetPolyShape( const SHAPE_POLY_SET& aShape ) { m_Poly = aShape; }
void SetBezierPoints( const std::vector<wxPoint>& aPoints )

View File

@ -395,7 +395,7 @@ void DIALOG_PAD_PROPERTIES::OnPaintShowPanel( wxPaintEvent& event )
case S_POLYGON: // polygon
{
std::vector<wxPoint> poly = dummySegment.GetPolyPoints();
std::vector<wxPoint> poly = dummySegment.BuildPolyPointsList();
GRClosedPoly( NULL, &dc, poly.size(), &poly[0],
m_drawPadOutlineMode ? false : true,
primitive.m_Thickness, m_selectedColor, m_selectedColor );

View File

@ -3,8 +3,8 @@
*
* Copyright (C) 2009-2013 Lorenzo Mercantonio
* Copyright (C) 2014-2017 Cirilo Bernardo
* Copyright (C) 2013 Jean-Pierre Charras jp.charras at wanadoo.fr
* Copyright (C) 2004-2016 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2018 Jean-Pierre Charras jp.charras at wanadoo.fr
* Copyright (C) 2004-2018 KiCad Developers, see AUTHORS.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
@ -1031,13 +1031,15 @@ static void export_vrml_edge_module( MODEL_VRML& aModel, EDGE_MODULE* aOutline,
break;
case S_POLYGON:
if( aOutline->IsPolyShapeValid() )
{
VRML_LAYER* vl;
if( !GetLayer( aModel, layer, &vl ) )
break;
int nvert = aOutline->GetPolyPoints().size() - 1;
std::vector<wxPoint> poly = aOutline->BuildPolyPointsList();
int nvert = poly.size() - 1;
int i = 0;
if( nvert < 3 ) break;
@ -1049,7 +1051,7 @@ static void export_vrml_edge_module( MODEL_VRML& aModel, EDGE_MODULE* aOutline,
while( i < nvert )
{
CPolyPt corner( aOutline->GetPolyPoints()[i] );
CPolyPt corner( poly[i] );
RotatePoint( &corner.x, &corner.y, aOrientation );
corner.x += aOutline->GetPosition().x;
corner.y += aOutline->GetPosition().y;

View File

@ -870,8 +870,6 @@ void PCB_IO::format( DIMENSION* aDimension, int aNestLevel ) const
void PCB_IO::format( DRAWSEGMENT* aSegment, int aNestLevel ) const
{
unsigned i;
switch( aSegment->GetShape() )
{
case S_SEGMENT: // Line
@ -898,12 +896,21 @@ void PCB_IO::format( DRAWSEGMENT* aSegment, int aNestLevel ) const
break;
case S_POLYGON: // Polygon
m_out->Print( aNestLevel, "(gr_poly (pts" );
if( aSegment->IsPolyShapeValid() )
{
SHAPE_POLY_SET& poly = aSegment->GetPolyShape();
SHAPE_LINE_CHAIN& outline = poly.Outline( 0 );
int pointsCount = outline.PointCount();
for( i = 0; i < aSegment->GetPolyPoints().size(); ++i )
m_out->Print( 0, " (xy %s)", FMT_IU( aSegment->GetPolyPoints()[i] ).c_str() );
m_out->Print( aNestLevel, "(gr_poly (pts" );
m_out->Print( 0, ")" );
for( int ii = 0; ii < pointsCount; ++ii )
{
m_out->Print( 0, " (xy %s)", FMT_IU( outline.CPoint( ii ) ).c_str() );
}
m_out->Print( 0, ")" );
}
break;
case S_CURVE: // Bezier curve
@ -955,24 +962,31 @@ void PCB_IO::format( EDGE_MODULE* aModuleDrawing, int aNestLevel ) const
FMT_ANGLE( aModuleDrawing->GetAngle() ).c_str() );
break;
case S_POLYGON: // Polygon
m_out->Print( aNestLevel, "(fp_poly (pts" );
for( unsigned i = 0; i < aModuleDrawing->GetPolyPoints().size(); ++i )
case S_POLYGON: // Polygonal segment
if( aModuleDrawing->IsPolyShapeValid() )
{
int nestLevel = 0;
SHAPE_POLY_SET& poly = aModuleDrawing->GetPolyShape();
SHAPE_LINE_CHAIN& outline = poly.Outline( 0 );
int pointsCount = outline.PointCount();
if( i && !(i%4) ) // newline every 4(pts)
m_out->Print( aNestLevel, "(fp_poly (pts" );
for( int ii = 0; ii < pointsCount; ++ii )
{
nestLevel = aNestLevel + 1;
m_out->Print( 0, "\n" );
int nestLevel = 0;
if( ii && !( ii%4 ) ) // newline every 4 pts
{
nestLevel = aNestLevel + 1;
m_out->Print( 0, "\n" );
}
m_out->Print( nestLevel, "%s(xy %s)",
nestLevel ? "" : " ", FMT_IU( outline.CPoint( ii ) ).c_str() );
}
m_out->Print( nestLevel, "%s(xy %s)",
nestLevel ? "" : " ",
FMT_IU( aModuleDrawing->GetPolyPoints()[i] ).c_str() );
m_out->Print( 0, ")" );
}
m_out->Print( 0, ")" );
break;
case S_CURVE: // Bezier curve

View File

@ -931,7 +931,7 @@ void PCB_PAINTER::draw( const DRAWSEGMENT* aSegment, int aLayer )
case S_POLYGON:
{
const auto& points = aSegment->GetPolyPoints();
const auto& points = aSegment->BuildPolyPointsList();
std::deque<VECTOR2D> pointsList;
if( points.empty() )

View File

@ -2571,7 +2571,7 @@ D_PAD* PCB_PARSER::parseD_PAD( MODULE* aParent )
case T_gr_poly:
dummysegm = parseDRAWSEGMENT();
pad->AddPrimitive( dummysegm->GetPolyPoints(), dummysegm->GetWidth() );
pad->AddPrimitive( dummysegm->BuildPolyPointsList(), dummysegm->GetWidth() );
break;
default:

View File

@ -520,35 +520,33 @@ void BRDITEMS_PLOTTER::Plot_1_EdgeModule( EDGE_MODULE* aEdge )
break;
case S_POLYGON:
{
const std::vector<wxPoint>& polyPoints = aEdge->GetPolyPoints();
if( polyPoints.size() <= 1 ) // Malformed polygon
break;
// We must compute true coordinates from m_PolyList
// which are relative to module position, orientation 0
MODULE* module = aEdge->GetParentModule();
std::vector< wxPoint > cornerList;
cornerList.reserve( polyPoints.size() );
for( unsigned ii = 0; ii < polyPoints.size(); ii++ )
if( aEdge->IsPolyShapeValid() )
{
wxPoint corner = polyPoints[ii];
const std::vector<wxPoint>& polyPoints = aEdge->BuildPolyPointsList();
if( module )
// We must compute true coordinates from m_PolyList
// which are relative to module position, orientation 0
MODULE* module = aEdge->GetParentModule();
std::vector< wxPoint > cornerList;
cornerList.reserve( polyPoints.size() );
for( unsigned ii = 0; ii < polyPoints.size(); ii++ )
{
RotatePoint( &corner, module->GetOrientation() );
corner += module->GetPosition();
wxPoint corner = polyPoints[ii];
if( module )
{
RotatePoint( &corner, module->GetOrientation() );
corner += module->GetPosition();
}
cornerList.push_back( corner );
}
cornerList.push_back( corner );
m_plotter->PlotPoly( cornerList, FILLED_SHAPE, thickness, &gbr_metadata );
}
m_plotter->PlotPoly( cornerList, FILLED_SHAPE, thickness, &gbr_metadata );
}
break;
}
}

View File

@ -823,7 +823,7 @@ int DRAWING_TOOL::PlaceDXF( const TOOL_EVENT& aEvent )
modSeg->SetBezControl1( seg->GetBezControl1() );
modSeg->SetBezControl2( seg->GetBezControl2() );
modSeg->SetBezierPoints( seg->GetBezierPoints() );
modSeg->SetPolyPoints( seg->GetPolyPoints() );
modSeg->SetPolyShape( seg->GetPolyShape() );
modSeg->SetLocalCoord();
converted = modSeg;
break;

View File

@ -355,7 +355,7 @@ void GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos )
case S_POLYGON:
{
for( const auto& p : dseg->GetPolyPoints() )
for( const auto& p : dseg->BuildPolyPointsList() )
{
addAnchor( p, CORNER | SNAPPABLE, dseg );
}

View File

@ -404,7 +404,7 @@ int MODULE_EDITOR_TOOLS::CreatePadFromShapes( const TOOL_EVENT& aEvent )
shape.m_Radius = em->GetRadius();
shape.m_Thickness = em->GetWidth();
shape.m_ArcAngle = em->GetAngle();
shape.m_Poly = em->GetPolyPoints();
shape.m_Poly = em->BuildPolyPointsList();
shapes.push_back(shape);

View File

@ -617,7 +617,7 @@ void POINT_EDITOR::updatePoints()
case S_POLYGON:
{
const auto& points = segment->GetPolyPoints();
const auto& points = segment->BuildPolyPointsList();
for( unsigned i = 0; i < points.size(); i++ )
{
m_editPoints->Point( i ).SetPosition( points[i] );