Fix assert where geometry routine wasn't ready to handle layers.

This introduces layer handling to a lot of the geometry routines.
Many of them don't do much with it now, but it does help multi-layer
zones and will help when padstacks are implemented.
This commit is contained in:
Jeff Young 2020-08-12 22:18:13 +01:00
parent 463100d67f
commit 393bb0fd83
28 changed files with 115 additions and 88 deletions

View File

@ -579,6 +579,7 @@ class BOARD_ADAPTER
void createNewPadWithClearance( const D_PAD *aPad, void createNewPadWithClearance( const D_PAD *aPad,
CGENERICCONTAINER2D *aDstContainer, CGENERICCONTAINER2D *aDstContainer,
PCB_LAYER_ID aLayer,
wxSize aClearanceValue ) const; wxSize aClearanceValue ) const;
COBJECT2D *createNewPadDrill( const D_PAD* aPad, int aInflateValue ); COBJECT2D *createNewPadDrill( const D_PAD* aPad, int aInflateValue );

View File

@ -81,7 +81,7 @@ void addTextSegmToContainer( int x0, int y0, int xf, int yf, void* aData )
// Based on // Based on
// void TEXTE_PCB::TransformShapeWithClearanceToPolygonSet // void TEXTE_PCB::TransformShapeWithClearanceToPolygon
// board_items_to_polygon_shape_transform.cpp // board_items_to_polygon_shape_transform.cpp
void BOARD_ADAPTER::AddShapeWithClearanceToContainer( const TEXTE_PCB* aText, void BOARD_ADAPTER::AddShapeWithClearanceToContainer( const TEXTE_PCB* aText,
CGENERICCONTAINER2D *aDstContainer, CGENERICCONTAINER2D *aDstContainer,
@ -314,6 +314,7 @@ void BOARD_ADAPTER::createNewTrack( const TRACK* aTrack, CGENERICCONTAINER2D *aD
void BOARD_ADAPTER::createNewPadWithClearance( const D_PAD* aPad, void BOARD_ADAPTER::createNewPadWithClearance( const D_PAD* aPad,
CGENERICCONTAINER2D *aDstContainer, CGENERICCONTAINER2D *aDstContainer,
PCB_LAYER_ID aLayer,
wxSize aClearanceValue ) const wxSize aClearanceValue ) const
{ {
SHAPE_POLY_SET poly; SHAPE_POLY_SET poly;
@ -325,7 +326,7 @@ void BOARD_ADAPTER::createNewPadWithClearance( const D_PAD* aPad,
// we fake a larger pad and run the general-purpose polygon builder on it. // we fake a larger pad and run the general-purpose polygon builder on it.
D_PAD dummy( *aPad ); D_PAD dummy( *aPad );
dummy.SetSize( aPad->GetSize() + aClearanceValue + aClearanceValue ); dummy.SetSize( aPad->GetSize() + aClearanceValue + aClearanceValue );
dummy.TransformShapeWithClearanceToPolygon( poly, 0 ); dummy.TransformShapeWithClearanceToPolygon( poly, aLayer, 0 );
} }
else else
{ {
@ -508,7 +509,7 @@ void BOARD_ADAPTER::AddPadsShapesWithClearanceToContainer( const MODULE* aModule
break; break;
} }
createNewPadWithClearance( pad, aDstContainer, margin ); createNewPadWithClearance( pad, aDstContainer, aLayerId, margin );
} }
} }
@ -648,7 +649,8 @@ void BOARD_ADAPTER::AddShapeWithClearanceToContainer( const DRAWSEGMENT* aDrawSe
{ {
SHAPE_POLY_SET polyList; SHAPE_POLY_SET polyList;
aDrawSegment->TransformShapeWithClearanceToPolygon( polyList, aClearanceValue ); aDrawSegment->TransformShapeWithClearanceToPolygon( polyList, aLayerId,
aClearanceValue );
polyList.Simplify( SHAPE_POLY_SET::PM_FAST ); polyList.Simplify( SHAPE_POLY_SET::PM_FAST );
@ -701,7 +703,7 @@ void BOARD_ADAPTER::AddShapeWithClearanceToContainer( const DRAWSEGMENT* aDrawSe
{ {
SHAPE_POLY_SET polyList; SHAPE_POLY_SET polyList;
aDrawSegment->TransformShapeWithClearanceToPolygon( polyList, aClearanceValue ); aDrawSegment->TransformShapeWithClearanceToPolygon( polyList, aLayerId, aClearanceValue );
polyList.Simplify( SHAPE_POLY_SET::PM_FAST ); polyList.Simplify( SHAPE_POLY_SET::PM_FAST );

View File

@ -466,7 +466,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
continue; continue;
// Add the track/via contour // Add the track/via contour
track->TransformShapeWithClearanceToPolygon( *layerPoly, 0 ); track->TransformShapeWithClearanceToPolygon( *layerPoly, curr_layer_id, 0 );
} }
} }
} }
@ -681,7 +681,8 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
switch( item->Type() ) switch( item->Type() )
{ {
case PCB_LINE_T: case PCB_LINE_T:
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( *layerPoly, 0 ); ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( *layerPoly,
cur_layer_id, 0 );
break; break;
case PCB_TEXT_T: case PCB_TEXT_T:
@ -960,7 +961,8 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
switch( item->Type() ) switch( item->Type() )
{ {
case PCB_LINE_T: case PCB_LINE_T:
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( *layerPoly, 0 ); ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( *layerPoly,
curr_layer_id, 0 );
break; break;
case PCB_TEXT_T: case PCB_TEXT_T:

View File

@ -71,7 +71,7 @@ void BOARD_ADAPTER::transformGraphicModuleEdgeToPolygonSet( const MODULE *aModul
EDGE_MODULE* outline = (EDGE_MODULE*) item; EDGE_MODULE* outline = (EDGE_MODULE*) item;
if( outline->GetLayer() == aLayer ) if( outline->GetLayer() == aLayer )
outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, 0 ); outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, aLayer, 0 );
} }
} }
} }

View File

@ -356,7 +356,10 @@ public:
* for visualization * for visualization
*/ */
virtual void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, virtual void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue, int aError = ARC_LOW_DEF, bool ignoreLineWidth = false ) const; PCB_LAYER_ID aLayer,
int aClearanceValue,
int aError = ARC_LOW_DEF,
bool ignoreLineWidth = false ) const;
struct ptr_cmp struct ptr_cmp
{ {

View File

@ -1619,7 +1619,8 @@ void ALTIUM_PCB::ParseArcs6Data(
zone->SetDoNotAllowFootprints( false ); zone->SetDoNotAllowFootprints( false );
zone->SetDoNotAllowCopperPour( true ); zone->SetDoNotAllowCopperPour( true );
ds.TransformShapeWithClearanceToPolygon( *zone->Outline(), 0, ARC_HIGH_DEF, false ); ds.TransformShapeWithClearanceToPolygon( *zone->Outline(), klayer, 0, ARC_HIGH_DEF,
false );
zone->Outline()->Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); // the outline is not a single polygon! zone->Outline()->Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); // the outline is not a single polygon!
zone->SetBorderDisplayStyle( ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE, zone->SetBorderDisplayStyle( ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE,
@ -2173,7 +2174,8 @@ void ALTIUM_PCB::ParseTracks6Data(
zone->SetDoNotAllowFootprints( false ); zone->SetDoNotAllowFootprints( false );
zone->SetDoNotAllowCopperPour( true ); zone->SetDoNotAllowCopperPour( true );
ds.TransformShapeWithClearanceToPolygon( *zone->Outline(), 0, ARC_HIGH_DEF, false ); ds.TransformShapeWithClearanceToPolygon( *zone->Outline(), klayer, 0, ARC_HIGH_DEF,
false );
zone->SetBorderDisplayStyle( ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE, zone->SetBorderDisplayStyle( ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE,
ZONE_CONTAINER::GetDefaultHatchPitch(), true ); ZONE_CONTAINER::GetDefaultHatchPitch(), true );

View File

@ -73,7 +73,7 @@ void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer, SHAPE_POLY_
if( !track->IsOnLayer( aLayer ) ) if( !track->IsOnLayer( aLayer ) )
continue; continue;
track->TransformShapeWithClearanceToPolygon( aOutlines, 0 ); track->TransformShapeWithClearanceToPolygon( aOutlines, aLayer, 0 );
} }
// convert pads // convert pads
@ -103,7 +103,7 @@ void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer, SHAPE_POLY_
switch( item->Type() ) switch( item->Type() )
{ {
case PCB_LINE_T: case PCB_LINE_T:
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( aOutlines, 0 ); ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( aOutlines, aLayer, 0 );
break; break;
case PCB_TEXT_T: case PCB_TEXT_T:
@ -173,7 +173,7 @@ void MODULE::TransformPadsShapesWithClearanceToPolygon( PCB_LAYER_ID aLayer,
break; break;
} }
pad->TransformShapeWithClearanceToPolygon( aCornerBuffer, clearance ); pad->TransformShapeWithClearanceToPolygon( aCornerBuffer, aLayer, clearance );
} }
} }
@ -209,7 +209,7 @@ void MODULE::TransformGraphicShapesWithClearanceToPolygonSet( PCB_LAYER_ID aLaye
EDGE_MODULE* outline = (EDGE_MODULE*) item; EDGE_MODULE* outline = (EDGE_MODULE*) item;
if( aLayer != UNDEFINED_LAYER && outline->GetLayer() == aLayer ) if( aLayer != UNDEFINED_LAYER && outline->GetLayer() == aLayer )
outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, 0, aError ); outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, aLayer, 0, aError );
} }
} }
@ -354,9 +354,13 @@ void TEXTE_PCB::TransformShapeWithClearanceToPolygonSet( SHAPE_POLY_SET& aCorner
void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
PCB_LAYER_ID aLayer,
int aClearanceValue, int aError, int aClearanceValue, int aError,
bool ignoreLineWidth ) const bool ignoreLineWidth ) const
{ {
if( aLayer != m_Layer )
return;
int width = ignoreLineWidth ? 0 : m_Width; int width = ignoreLineWidth ? 0 : m_Width;
width += 2 * aClearanceValue; width += 2 * aClearanceValue;
@ -478,6 +482,7 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerB
void TRACK::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void TRACK::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
PCB_LAYER_ID aLayer,
int aClearanceValue, int aError, int aClearanceValue, int aError,
bool ignoreLineWidth ) const bool ignoreLineWidth ) const
{ {
@ -512,6 +517,7 @@ void TRACK::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
PCB_LAYER_ID aLayer,
int aClearanceValue, int aError, int aClearanceValue, int aError,
bool ignoreLineWidth ) const bool ignoreLineWidth ) const
{ {
@ -614,7 +620,7 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
case PAD_SHAPE_CUSTOM: case PAD_SHAPE_CUSTOM:
{ {
SHAPE_POLY_SET outline; SHAPE_POLY_SET outline;
MergePrimitivesAsPolygon( &outline ); MergePrimitivesAsPolygon( &outline, aLayer );
outline.Rotate( -DECIDEG2RAD( m_orient ) ); outline.Rotate( -DECIDEG2RAD( m_orient ) );
outline.Move( VECTOR2I( m_pos ) ); outline.Move( VECTOR2I( m_pos ) );
@ -663,19 +669,15 @@ bool D_PAD::TransformHoleWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
void ZONE_CONTAINER::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void ZONE_CONTAINER::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue, int aError, PCB_LAYER_ID aLayer, int aClearance,
bool ignoreLineWidth ) const int aError, bool ignoreLineWidth ) const
{ {
// Now that zones are multilayer, we cannot implement this without a layer argument. wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for zones." );
// But, at the time of adding multilayer zones, this is never called for zones anyway
// so let's just disable it and fail.
wxFAIL_MSG( "TransformShapeWithClearanceToPolygon is not supported for zones" );
#if 0
if( !m_FilledPolysList.count( aLayer ) ) if( !m_FilledPolysList.count( aLayer ) )
return; return;
aCornerBuffer = m_FilledPolysList.at( aLayer ); aCornerBuffer = m_FilledPolysList.at( aLayer );
aCornerBuffer.Inflate( aClearance, aError );
aCornerBuffer.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); aCornerBuffer.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
#endif
} }

View File

@ -132,6 +132,7 @@ void BOARD_ITEM::SwapData( BOARD_ITEM* aImage )
void BOARD_ITEM::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void BOARD_ITEM::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
PCB_LAYER_ID aLayer,
int aClearanceValue, int aError, int aClearanceValue, int aError,
bool ignoreLineWidth ) const bool ignoreLineWidth ) const
{ {

View File

@ -312,8 +312,9 @@ public:
* @param ignoreLineWidth = used for edge cut items where the line width is only * @param ignoreLineWidth = used for edge cut items where the line width is only
* for visualization * for visualization
*/ */
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, PCB_LAYER_ID aLayer,
int aError = ARC_HIGH_DEF, bool ignoreLineWidth = false ) const override; int aClearanceValue, int aError = ARC_HIGH_DEF,
bool ignoreLineWidth = false ) const override;
virtual wxString GetSelectMenuText( EDA_UNITS aUnits ) const override; virtual wxString GetSelectMenuText( EDA_UNITS aUnits ) const override;

View File

@ -246,19 +246,19 @@ void D_PAD::SetChamferRectRatio( double aChamferScale )
} }
const std::vector<std::shared_ptr<SHAPE>>& D_PAD::GetEffectiveShapes() const const std::vector<std::shared_ptr<SHAPE>>& D_PAD::GetEffectiveShapes( PCB_LAYER_ID aLayer ) const
{ {
if( m_shapesDirty ) if( m_shapesDirty )
BuildEffectiveShapes(); BuildEffectiveShapes( aLayer );
return m_effectiveShapes; return m_effectiveShapes;
} }
const std::shared_ptr<SHAPE_POLY_SET>& D_PAD::GetEffectivePolygon() const const std::shared_ptr<SHAPE_POLY_SET>& D_PAD::GetEffectivePolygon( PCB_LAYER_ID aLayer ) const
{ {
if( m_shapesDirty ) if( m_shapesDirty )
BuildEffectiveShapes(); BuildEffectiveShapes( aLayer );
return m_effectivePolygon; return m_effectivePolygon;
} }
@ -269,9 +269,9 @@ std::shared_ptr<SHAPE> D_PAD::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
std::shared_ptr<SHAPE_COMPOUND> shape( new SHAPE_COMPOUND ); std::shared_ptr<SHAPE_COMPOUND> shape( new SHAPE_COMPOUND );
if( m_shapesDirty ) if( m_shapesDirty )
BuildEffectiveShapes(); BuildEffectiveShapes( aLayer );
for( auto s : m_effectiveShapes ) for( std::shared_ptr<SHAPE>& s : m_effectiveShapes )
shape->AddShape( s->Clone() ); // fixme: use COMPOUND everywhere shape->AddShape( s->Clone() ); // fixme: use COMPOUND everywhere
return shape; return shape;
@ -281,7 +281,7 @@ std::shared_ptr<SHAPE> D_PAD::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
const SHAPE_SEGMENT* D_PAD::GetEffectiveHoleShape() const const SHAPE_SEGMENT* D_PAD::GetEffectiveHoleShape() const
{ {
if( m_shapesDirty ) if( m_shapesDirty )
BuildEffectiveShapes(); BuildEffectiveShapes( UNDEFINED_LAYER );
return m_effectiveHoleShape.get(); return m_effectiveHoleShape.get();
} }
@ -290,13 +290,13 @@ const SHAPE_SEGMENT* D_PAD::GetEffectiveHoleShape() const
int D_PAD::GetBoundingRadius() const int D_PAD::GetBoundingRadius() const
{ {
if( m_shapesDirty ) if( m_shapesDirty )
BuildEffectiveShapes(); BuildEffectiveShapes( UNDEFINED_LAYER );
return m_effectiveBoundingRadius; return m_effectiveBoundingRadius;
} }
void D_PAD::BuildEffectiveShapes() const void D_PAD::BuildEffectiveShapes( PCB_LAYER_ID aLayer ) const
{ {
m_effectiveShapes.clear(); m_effectiveShapes.clear();
m_effectiveHoleShape = nullptr; m_effectiveHoleShape = nullptr;
@ -420,10 +420,13 @@ void D_PAD::BuildEffectiveShapes() const
// Polygon // Polygon
// //
m_effectivePolygon = std::make_shared<SHAPE_POLY_SET>(); m_effectivePolygon = std::make_shared<SHAPE_POLY_SET>();
TransformShapeWithClearanceToPolygon( *m_effectivePolygon, 0 ); TransformShapeWithClearanceToPolygon( *m_effectivePolygon, aLayer, 0 );
// Bounding box and radius // Bounding box and radius
// //
// PADSTACKS TODO: these will both need to cycle through all layers to get the largest
// values....
//
m_effectiveBoundingRadius = 0; m_effectiveBoundingRadius = 0;
for( int cnt = 0; cnt < m_effectivePolygon->OutlineCount(); ++cnt ) for( int cnt = 0; cnt < m_effectivePolygon->OutlineCount(); ++cnt )
@ -468,7 +471,7 @@ void D_PAD::BuildEffectiveShapes() const
const EDA_RECT D_PAD::GetBoundingBox() const const EDA_RECT D_PAD::GetBoundingBox() const
{ {
if( m_shapesDirty ) if( m_shapesDirty )
BuildEffectiveShapes(); BuildEffectiveShapes( UNDEFINED_LAYER );
return m_effectiveBoundingBox; return m_effectiveBoundingBox;
} }

View File

@ -260,7 +260,7 @@ public:
* Merge all basic shapes to a SHAPE_POLY_SET * Merge all basic shapes to a SHAPE_POLY_SET
* Note: The corners coordinates are relative to the pad position, orientation 0, * Note: The corners coordinates are relative to the pad position, orientation 0,
*/ */
void MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon ) const; void MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon, PCB_LAYER_ID aLayer ) const;
/** /**
* clear the basic shapes list * clear the basic shapes list
@ -367,8 +367,8 @@ public:
* @param aMaxError = maximum error from true when converting arcs * @param aMaxError = maximum error from true when converting arcs
* @param ignoreLineWidth = used for edge cuts where the line width is only for visualization * @param ignoreLineWidth = used for edge cuts where the line width is only for visualization
*/ */
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, PCB_LAYER_ID aLayer,
int aMaxError = ARC_HIGH_DEF, int aClearanceValue, int aMaxError = ARC_HIGH_DEF,
bool ignoreLineWidth = false ) const override; bool ignoreLineWidth = false ) const override;
/** /**
@ -385,9 +385,9 @@ public:
// @copydoc BOARD_ITEM::GetEffectiveShape // @copydoc BOARD_ITEM::GetEffectiveShape
virtual std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ) const override; virtual std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ) const override;
const std::vector<std::shared_ptr<SHAPE>>& GetEffectiveShapes() const; const std::vector<std::shared_ptr<SHAPE>>& GetEffectiveShapes( PCB_LAYER_ID = UNDEFINED_LAYER ) const;
const std::shared_ptr<SHAPE_POLY_SET>& GetEffectivePolygon() const; const std::shared_ptr<SHAPE_POLY_SET>& GetEffectivePolygon( PCB_LAYER_ID = UNDEFINED_LAYER ) const;
/** /**
* Function GetEffectiveHoleShape * Function GetEffectiveHoleShape
@ -604,7 +604,7 @@ public:
* Rebuilds the effective shape cache (and bounding box and radius) for the pad and clears * Rebuilds the effective shape cache (and bounding box and radius) for the pad and clears
* the dirty bit. * the dirty bit.
*/ */
void BuildEffectiveShapes() const; void BuildEffectiveShapes( PCB_LAYER_ID aLayer ) const;
virtual void ViewGetLayers( int aLayers[], int& aCount ) const override; virtual void ViewGetLayers( int aLayers[], int& aCount ) const override;
@ -620,7 +620,8 @@ public:
private: private:
void addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError ) const; void addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, PCB_LAYER_ID aLayer,
int aError ) const;
private: private:
wxString m_name; // Pad name (pin number in schematic) wxString m_name; // Pad name (pin number in schematic)

View File

@ -116,7 +116,9 @@ void PCB_GROUP::SwapData( BOARD_ITEM* aImage )
#if 0 #if 0
void PCB_GROUP::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void PCB_GROUP::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue, int aError = ARC_LOW_DEF, bool ignoreLineWidth = false ) const PCB_LAYER_ID aLayer, int aClearanceValue,
int aError = ARC_LOW_DEF,
bool ignoreLineWidth = false ) const
{ {
} }
const BOX2I PCB_GROUP::ViewBBox() const const BOX2I PCB_GROUP::ViewBBox() const

View File

@ -164,8 +164,9 @@ public:
* @param ignoreLineWidth = used for edge cut items where the line width is only * @param ignoreLineWidth = used for edge cut items where the line width is only
* for visualization * for visualization
*/ */
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, PCB_LAYER_ID aLayer,
int aError = ARC_HIGH_DEF, bool ignoreLineWidth = false ) const override; int aClearanceValue, int aError = ARC_HIGH_DEF,
bool ignoreLineWidth = false ) const override;
/** /**
* Function IsPointOnEnds * Function IsPointOnEnds
* returns STARTPOINT if point if near (dist = min_dist) start point, ENDPOINT if * returns STARTPOINT if point if near (dist = min_dist) start point, ENDPOINT if

View File

@ -363,7 +363,7 @@ public:
* @param ignoreLineWidth = used for edge cut items where the line width is only * @param ignoreLineWidth = used for edge cut items where the line width is only
* for visualization * for visualization
*/ */
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, PCB_LAYER_ID aLayer,
int aClearanceValue, int aError = ARC_HIGH_DEF, int aClearanceValue, int aError = ARC_HIGH_DEF,
bool ignoreLineWidth = false ) const override; bool ignoreLineWidth = false ) const override;

View File

@ -1187,10 +1187,11 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
} }
} }
// PADSTACKS TODO: this will need to check each layer in the pad...
if( m_dummyPad->GetShape() == PAD_SHAPE_CUSTOM ) if( m_dummyPad->GetShape() == PAD_SHAPE_CUSTOM )
{ {
SHAPE_POLY_SET mergedPolygon; SHAPE_POLY_SET mergedPolygon;
m_dummyPad->MergePrimitivesAsPolygon( &mergedPolygon ); m_dummyPad->MergePrimitivesAsPolygon( &mergedPolygon, UNDEFINED_LAYER );
if( mergedPolygon.OutlineCount() > 1 ) if( mergedPolygon.OutlineCount() > 1 )
error_msgs.Add( _( "Incorrect pad shape: the shape must be equivalent to only one polygon" ) ); error_msgs.Add( _( "Incorrect pad shape: the shape must be equivalent to only one polygon" ) );

View File

@ -298,7 +298,7 @@ bool DRC_KEEPOUT_TESTER::checkDrawings()
continue; continue;
SHAPE_POLY_SET poly; SHAPE_POLY_SET poly;
drawing->TransformShapeWithClearanceToPolygon( poly, 0 ); drawing->TransformShapeWithClearanceToPolygon( poly, drawing->GetLayer(), 0 );
// Build the common area between footprint and the keepout area: // Build the common area between footprint and the keepout area:
poly.BooleanIntersection( *m_zone->Outline(), SHAPE_POLY_SET::PM_FAST ); poly.BooleanIntersection( *m_zone->Outline(), SHAPE_POLY_SET::PM_FAST );

View File

@ -585,7 +585,7 @@ static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb )
fprintf( aFile, " POLYGON %g\n", pad->GetDrillSize().x / SCALE_FACTOR ); fprintf( aFile, " POLYGON %g\n", pad->GetDrillSize().x / SCALE_FACTOR );
SHAPE_POLY_SET outline; SHAPE_POLY_SET outline;
pad->MergePrimitivesAsPolygon( &outline ); pad->MergePrimitivesAsPolygon( &outline, UNDEFINED_LAYER );
for( int jj = 0; jj < outline.OutlineCount(); ++jj ) for( int jj = 0; jj < outline.OutlineCount(); ++jj )
{ {

View File

@ -1174,7 +1174,7 @@ static void export_vrml_padshape( MODEL_VRML& aModel, VRML_LAYER* aTinLayer, D_P
{ {
SHAPE_POLY_SET polySet; SHAPE_POLY_SET polySet;
std::vector< wxRealPoint > cornerList; std::vector< wxRealPoint > cornerList;
aPad->MergePrimitivesAsPolygon( &polySet ); aPad->MergePrimitivesAsPolygon( &polySet, UNDEFINED_LAYER );
for( int cnt = 0; cnt < polySet.OutlineCount(); ++cnt ) for( int cnt = 0; cnt < polySet.OutlineCount(); ++cnt )
{ {

View File

@ -175,12 +175,13 @@ void D_PAD::DeletePrimitivesList()
} }
void D_PAD::addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError ) const void D_PAD::addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, PCB_LAYER_ID aLayer,
int aError ) const
{ {
SHAPE_POLY_SET polyset; SHAPE_POLY_SET polyset;
for( const std::shared_ptr<DRAWSEGMENT>& primitive : m_editPrimitives ) for( const std::shared_ptr<DRAWSEGMENT>& primitive : m_editPrimitives )
primitive->TransformShapeWithClearanceToPolygon( polyset, 0, aError ); primitive->TransformShapeWithClearanceToPolygon( polyset, aLayer, 0, aError );
polyset.Simplify( SHAPE_POLY_SET::PM_FAST ); polyset.Simplify( SHAPE_POLY_SET::PM_FAST );
@ -192,7 +193,7 @@ void D_PAD::addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aErro
} }
} }
void D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon ) const void D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon, PCB_LAYER_ID aLayer ) const
{ {
auto board = GetBoard(); auto board = GetBoard();
int maxError = ARC_HIGH_DEF; int maxError = ARC_HIGH_DEF;
@ -219,14 +220,14 @@ void D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon ) const
break; break;
} }
addPadPrimitivesToPolygon( aMergedPolygon, maxError ); addPadPrimitivesToPolygon( aMergedPolygon, aLayer, maxError );
} }
bool D_PAD::GetBestAnchorPosition( VECTOR2I& aPos ) bool D_PAD::GetBestAnchorPosition( VECTOR2I& aPos )
{ {
SHAPE_POLY_SET poly; SHAPE_POLY_SET poly;
addPadPrimitivesToPolygon( &poly, ARC_LOW_DEF ); addPadPrimitivesToPolygon( &poly, UNDEFINED_LAYER, ARC_LOW_DEF );
if( poly.OutlineCount() > 1 ) if( poly.OutlineCount() > 1 )
return false; return false;

View File

@ -131,7 +131,7 @@ static void insideCourtyard( LIBEVAL::CONTEXT* aCtx, void* self )
SHAPE_POLY_SET testPoly; SHAPE_POLY_SET testPoly;
item->TransformShapeWithClearanceToPolygon( testPoly, 0 ); item->TransformShapeWithClearanceToPolygon( testPoly, context->GetLayer(), 0 );
testPoly.BooleanIntersection( footprintCourtyard, SHAPE_POLY_SET::PM_FAST ); testPoly.BooleanIntersection( footprintCourtyard, SHAPE_POLY_SET::PM_FAST );
if( testPoly.OutlineCount() ) if( testPoly.OutlineCount() )
@ -188,7 +188,7 @@ static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
SHAPE_POLY_SET zonePoly = zone->GetFilledPolysList( context->GetLayer() ); SHAPE_POLY_SET zonePoly = zone->GetFilledPolysList( context->GetLayer() );
SHAPE_POLY_SET testPoly; SHAPE_POLY_SET testPoly;
item->TransformShapeWithClearanceToPolygon( testPoly, 0 ); item->TransformShapeWithClearanceToPolygon( testPoly, context->GetLayer(), 0 );
testPoly.BooleanIntersection( zonePoly, SHAPE_POLY_SET::PM_FAST ); testPoly.BooleanIntersection( zonePoly, SHAPE_POLY_SET::PM_FAST );
if( testPoly.OutlineCount() ) if( testPoly.OutlineCount() )

View File

@ -902,7 +902,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
else else
{ {
SHAPE_POLY_SET polySet; SHAPE_POLY_SET polySet;
pad->TransformShapeWithClearanceToPolygon( polySet, margin.x ); pad->TransformShapeWithClearanceToPolygon( polySet, ToLAYER_ID( aLayer ), margin.x );
m_gal->DrawPolygon( polySet ); m_gal->DrawPolygon( polySet );
} }
@ -940,7 +940,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
else else
{ {
SHAPE_POLY_SET polySet; SHAPE_POLY_SET polySet;
pad->TransformShapeWithClearanceToPolygon( polySet, clearance ); pad->TransformShapeWithClearanceToPolygon( polySet, ToLAYER_ID( aLayer ), clearance );
m_gal->DrawPolygon( polySet ); m_gal->DrawPolygon( polySet );
} }
} }

View File

@ -339,7 +339,7 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
// so build a similar pad shape, and inflate/deflate the polygonal shape // so build a similar pad shape, and inflate/deflate the polygonal shape
D_PAD dummy( *pad ); D_PAD dummy( *pad );
SHAPE_POLY_SET shape; SHAPE_POLY_SET shape;
pad->MergePrimitivesAsPolygon( &shape ); pad->MergePrimitivesAsPolygon( &shape, UNDEFINED_LAYER );
// Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate() // Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
// which can create bad shapes if margin.x is < 0 // which can create bad shapes if margin.x is < 0
int maxError = aBoard->GetDesignSettings().m_MaxError; int maxError = aBoard->GetDesignSettings().m_MaxError;
@ -850,9 +850,9 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
continue; continue;
// add shapes with their exact mask layer size in initialPolys // add shapes with their exact mask layer size in initialPolys
via->TransformShapeWithClearanceToPolygon( initialPolys, via_clearance ); via->TransformShapeWithClearanceToPolygon( initialPolys, layer, via_clearance );
// add shapes inflated by aMinThickness/2 in areas // add shapes inflated by aMinThickness/2 in areas
via->TransformShapeWithClearanceToPolygon( areas, via_margin ); via->TransformShapeWithClearanceToPolygon( areas, layer, via_margin );
} }
} }

View File

@ -535,7 +535,7 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
{ {
std::vector<wxPoint> polygonal_shape; std::vector<wxPoint> polygonal_shape;
SHAPE_POLY_SET pad_shape; SHAPE_POLY_SET pad_shape;
aPad->MergePrimitivesAsPolygon( &pad_shape ); aPad->MergePrimitivesAsPolygon( &pad_shape, UNDEFINED_LAYER );
#ifdef EXPORT_CUSTOM_PADS_CONVEX_HULL #ifdef EXPORT_CUSTOM_PADS_CONVEX_HULL
BuildConvexHull( polygonal_shape, pad_shape ); BuildConvexHull( polygonal_shape, pad_shape );

View File

@ -607,7 +607,7 @@ void PAD_TOOL::recombinePad( D_PAD* aPad )
auto findNext = [&]( PCB_LAYER_ID aLayer ) -> EDGE_MODULE* auto findNext = [&]( PCB_LAYER_ID aLayer ) -> EDGE_MODULE*
{ {
SHAPE_POLY_SET padPoly; SHAPE_POLY_SET padPoly;
aPad->TransformShapeWithClearanceToPolygon( padPoly, 0 ); aPad->TransformShapeWithClearanceToPolygon( padPoly, aLayer, 0 );
for( BOARD_ITEM* item : board()->GetFirstModule()->GraphicalItems() ) for( BOARD_ITEM* item : board()->GetFirstModule()->GraphicalItems() )
{ {
@ -620,7 +620,7 @@ void PAD_TOOL::recombinePad( D_PAD* aPad )
continue; continue;
SHAPE_POLY_SET drawPoly; SHAPE_POLY_SET drawPoly;
draw->TransformShapeWithClearanceToPolygon( drawPoly, 0 ); draw->TransformShapeWithClearanceToPolygon( drawPoly, aLayer, 0 );
drawPoly.BooleanIntersection( padPoly, SHAPE_POLY_SET::PM_FAST ); drawPoly.BooleanIntersection( padPoly, SHAPE_POLY_SET::PM_FAST );
if( !drawPoly.IsEmpty() ) if( !drawPoly.IsEmpty() )
@ -657,7 +657,7 @@ void PAD_TOOL::recombinePad( D_PAD* aPad )
// to a polygon primitive // to a polygon primitive
SHAPE_POLY_SET existingOutline; SHAPE_POLY_SET existingOutline;
int maxError = board()->GetDesignSettings().m_MaxError; int maxError = board()->GetDesignSettings().m_MaxError;
aPad->TransformShapeWithClearanceToPolygon( existingOutline, 0, maxError ); aPad->TransformShapeWithClearanceToPolygon( existingOutline, layer, 0, maxError );
aPad->SetAnchorPadShape( PAD_SHAPE_CIRCLE ); aPad->SetAnchorPadShape( PAD_SHAPE_CIRCLE );
wxSize minAnnulus( Millimeter2iu( 0.2 ), Millimeter2iu( 0.2 ) ); wxSize minAnnulus( Millimeter2iu( 0.2 ), Millimeter2iu( 0.2 ) );

View File

@ -331,7 +331,7 @@ void TRACKS_CLEANER::deleteTracksInPads()
if( pad->HitTest( track->GetStart() ) && pad->HitTest( track->GetEnd() ) ) if( pad->HitTest( track->GetStart() ) && pad->HitTest( track->GetEnd() ) )
{ {
SHAPE_POLY_SET poly; SHAPE_POLY_SET poly;
track->TransformShapeWithClearanceToPolygon( poly, 0 ); track->TransformShapeWithClearanceToPolygon( poly, track->GetLayer(), 0 );
poly.BooleanSubtract( *pad->GetEffectivePolygon(), SHAPE_POLY_SET::PM_FAST ); poly.BooleanSubtract( *pad->GetEffectivePolygon(), SHAPE_POLY_SET::PM_FAST );

View File

@ -131,7 +131,7 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck
for( auto pad : module->Pads() ) for( auto pad : module->Pads() )
{ {
if( pad->IsDirty() ) if( pad->IsDirty() )
pad->BuildEffectiveShapes(); pad->BuildEffectiveShapes( UNDEFINED_LAYER );
} }
} }
@ -439,12 +439,12 @@ static void setupDummyPadForHole( const D_PAD* aPad, D_PAD& aDummyPad )
* Add a knockout for a pad. The knockout is 'aGap' larger than the pad (which might be * Add a knockout for a pad. The knockout is 'aGap' larger than the pad (which might be
* either the thermal clearance or the electrical clearance). * either the thermal clearance or the electrical clearance).
*/ */
void ZONE_FILLER::addKnockout( D_PAD* aPad, int aGap, SHAPE_POLY_SET& aHoles ) void ZONE_FILLER::addKnockout( D_PAD* aPad, PCB_LAYER_ID aLayer, int aGap, SHAPE_POLY_SET& aHoles )
{ {
if( aPad->GetShape() == PAD_SHAPE_CUSTOM ) if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
{ {
SHAPE_POLY_SET poly; SHAPE_POLY_SET poly;
aPad->TransformShapeWithClearanceToPolygon( poly, aGap, m_high_def ); aPad->TransformShapeWithClearanceToPolygon( poly, aLayer, aGap, m_high_def );
// the pad shape in zone can be its convex hull or the shape itself // the pad shape in zone can be its convex hull or the shape itself
if( aPad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL ) if( aPad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
@ -467,9 +467,9 @@ void ZONE_FILLER::addKnockout( D_PAD* aPad, int aGap, SHAPE_POLY_SET& aHoles )
// small arcs) // small arcs)
if( aPad->GetShape() == PAD_SHAPE_CIRCLE || aPad->GetShape() == PAD_SHAPE_OVAL || if( aPad->GetShape() == PAD_SHAPE_CIRCLE || aPad->GetShape() == PAD_SHAPE_OVAL ||
( aPad->GetShape() == PAD_SHAPE_ROUNDRECT && aPad->GetRoundRectRadiusRatio() > 0.4 ) ) ( aPad->GetShape() == PAD_SHAPE_ROUNDRECT && aPad->GetRoundRectRadiusRatio() > 0.4 ) )
aPad->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_high_def ); aPad->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_high_def );
else else
aPad->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_low_def ); aPad->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_low_def );
} }
} }
@ -478,15 +478,16 @@ void ZONE_FILLER::addKnockout( D_PAD* aPad, int aGap, SHAPE_POLY_SET& aHoles )
* Add a knockout for a graphic item. The knockout is 'aGap' larger than the item (which * Add a knockout for a graphic item. The knockout is 'aGap' larger than the item (which
* might be either the electrical clearance or the board edge clearance). * might be either the electrical clearance or the board edge clearance).
*/ */
void ZONE_FILLER::addKnockout( BOARD_ITEM* aItem, int aGap, bool aIgnoreLineWidth, void ZONE_FILLER::addKnockout( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int aGap,
SHAPE_POLY_SET& aHoles ) bool aIgnoreLineWidth, SHAPE_POLY_SET& aHoles )
{ {
switch( aItem->Type() ) switch( aItem->Type() )
{ {
case PCB_LINE_T: case PCB_LINE_T:
{ {
DRAWSEGMENT* seg = (DRAWSEGMENT*) aItem; DRAWSEGMENT* seg = (DRAWSEGMENT*) aItem;
seg->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_high_def, aIgnoreLineWidth ); seg->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_high_def,
aIgnoreLineWidth );
break; break;
} }
case PCB_TEXT_T: case PCB_TEXT_T:
@ -498,7 +499,8 @@ void ZONE_FILLER::addKnockout( BOARD_ITEM* aItem, int aGap, bool aIgnoreLineWidt
case PCB_MODULE_EDGE_T: case PCB_MODULE_EDGE_T:
{ {
EDGE_MODULE* edge = (EDGE_MODULE*) aItem; EDGE_MODULE* edge = (EDGE_MODULE*) aItem;
edge->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_high_def, aIgnoreLineWidth ); edge->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_high_def,
aIgnoreLineWidth );
break; break;
} }
case PCB_MODULE_TEXT_T: case PCB_MODULE_TEXT_T:
@ -550,7 +552,7 @@ void ZONE_FILLER::knockoutThermalReliefs( const ZONE_CONTAINER* aZone, PCB_LAYER
pad = &dummypad; pad = &dummypad;
} }
addKnockout( pad, aZone->GetThermalReliefGap( pad ), holes ); addKnockout( pad, aLayer, aZone->GetThermalReliefGap( pad ), holes );
} }
} }
@ -620,7 +622,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
else else
gap = aZone->GetClearance( aLayer, pad ); gap = aZone->GetClearance( aLayer, pad );
addKnockout( pad, gap, aHoles ); addKnockout( pad, aLayer, gap, aHoles );
} }
} }
} }
@ -651,12 +653,12 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
} }
else else
{ {
via->TransformShapeWithClearanceToPolygon( aHoles, gap, m_low_def ); via->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap, m_low_def );
} }
} }
else else
{ {
track->TransformShapeWithClearanceToPolygon( aHoles, gap, m_low_def ); track->TransformShapeWithClearanceToPolygon( aHoles, aLayer, gap, m_low_def );
} }
} }
} }
@ -676,7 +678,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
bool ignoreLineWidth = aItem->IsOnLayer( Edge_Cuts ); bool ignoreLineWidth = aItem->IsOnLayer( Edge_Cuts );
int gap = aZone->GetClearance( aLayer, aItem ); int gap = aZone->GetClearance( aLayer, aItem );
addKnockout( aItem, gap, ignoreLineWidth, aHoles ); addKnockout( aItem, aLayer, gap, ignoreLineWidth, aHoles );
} }
}; };
@ -1291,7 +1293,8 @@ void ZONE_FILLER::addHatchFillTypeOnZone( const ZONE_CONTAINER* aZone, PCB_LAYER
outline_margin - min_annulus ); outline_margin - min_annulus );
clearance = std::max( 0, clearance - linethickness / 2 ); clearance = std::max( 0, clearance - linethickness / 2 );
pad->TransformShapeWithClearanceToPolygon( aprons, clearance, ARC_HIGH_DEF ); pad->TransformShapeWithClearanceToPolygon( aprons, aLayer, clearance,
ARC_HIGH_DEF );
} }
} }
} }

View File

@ -47,9 +47,10 @@ public:
private: private:
void addKnockout( D_PAD* aPad, int aGap, SHAPE_POLY_SET& aHoles ); void addKnockout( D_PAD* aPad, PCB_LAYER_ID aLayer, int aGap, SHAPE_POLY_SET& aHoles );
void addKnockout( BOARD_ITEM* aItem, int aGap, bool aIgnoreLineWidth, SHAPE_POLY_SET& aHoles ); void addKnockout( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int aGap, bool aIgnoreLineWidth,
SHAPE_POLY_SET& aHoles );
void knockoutThermalReliefs( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer, void knockoutThermalReliefs( const ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aFill ); SHAPE_POLY_SET& aFill );

View File

@ -46,7 +46,7 @@ void process( const BOARD_CONNECTED_ITEM* item, int net )
SHAPE_POLY_SET pset; SHAPE_POLY_SET pset;
item->TransformShapeWithClearanceToPolygon( pset, 1, ARC_HIGH_DEF ); item->TransformShapeWithClearanceToPolygon( pset, UNDEFINED_LAYER, 1, ARC_HIGH_DEF );
SHAPE_FILE_IO shapeIo; // default = stdout SHAPE_FILE_IO shapeIo; // default = stdout
shapeIo.Write( &pset ); shapeIo.Write( &pset );