From a8795711a05338e5aec59b2b991264c267f1ff9d Mon Sep 17 00:00:00 2001 From: Alex Shvartzkop Date: Sun, 26 Nov 2023 00:23:34 +0300 Subject: [PATCH] Altium PCB: import hatched polygon pour fills. --- pcbnew/plugins/altium/altium_parser_pcb.cpp | 17 +-- pcbnew/plugins/altium/altium_parser_pcb.h | 3 + pcbnew/plugins/altium/altium_pcb.cpp | 120 +++++++++++++++++--- 3 files changed, 117 insertions(+), 23 deletions(-) diff --git a/pcbnew/plugins/altium/altium_parser_pcb.cpp b/pcbnew/plugins/altium/altium_parser_pcb.cpp index 182d3fb44a..8b2ab91ecc 100644 --- a/pcbnew/plugins/altium/altium_parser_pcb.cpp +++ b/pcbnew/plugins/altium/altium_parser_pcb.cpp @@ -615,7 +615,7 @@ AARC6::AARC6( ALTIUM_PARSER& aReader ) is_keepout = flags2 == 2; net = aReader.Read(); - subpolyindex = aReader.Read(); + polygon = aReader.Read(); component = aReader.Read(); aReader.Skip( 4 ); center = aReader.ReadVector2IPos(); @@ -623,10 +623,11 @@ AARC6::AARC6( ALTIUM_PARSER& aReader ) startangle = aReader.Read(); endangle = aReader.Read(); width = aReader.ReadKicadUnit(); + subpolyindex = aReader.Read(); if( aReader.GetRemainingSubrecordBytes() >= 12 ) { - aReader.Skip( 11 ); + aReader.Skip( 9 ); keepoutrestrictions = aReader.Read(); } else @@ -888,16 +889,17 @@ ATRACK6::ATRACK6( ALTIUM_PARSER& aReader ) is_keepout = flags2 == 2; net = aReader.Read(); - subpolyindex = aReader.Read(); + polygon = aReader.Read(); component = aReader.Read(); aReader.Skip( 4 ); start = aReader.ReadVector2IPos(); end = aReader.ReadVector2IPos(); width = aReader.ReadKicadUnit(); + subpolyindex = aReader.Read(); if( aReader.GetRemainingSubrecordBytes() >= 13 ) { - aReader.Skip( 12 ); + aReader.Skip( 10 ); keepoutrestrictions = aReader.Read(); } else @@ -1038,7 +1040,7 @@ AREGION6::AREGION6( ALTIUM_PARSER& aReader, bool aExtendedVertices ) is_keepout = flags2 == 2; net = aReader.Read(); - subpolyindex = aReader.Read(); + polygon = aReader.Read(); component = aReader.Read(); aReader.Skip( 5 ); holecount = aReader.Read(); @@ -1057,8 +1059,9 @@ AREGION6::AREGION6( ALTIUM_PARSER& aReader, bool aExtendedVertices ) ALTIUM_PARSER::ReadInt( properties, wxT( "KEEPOUTRESTRIC" ), 0x1F ) ); // TODO: this can differ from the other subpolyindex?! - //subpolyindex = static_cast( - // ALTIUM_PARSER::ReadInt( properties, "SUBPOLYINDEX", ALTIUM_POLYGON_NONE ) ); + // Note: "the other subpolyindex" is "polygon" + subpolyindex = static_cast( + ALTIUM_PARSER::ReadInt( properties, "SUBPOLYINDEX", ALTIUM_POLYGON_NONE ) ); switch( pkind ) { diff --git a/pcbnew/plugins/altium/altium_parser_pcb.h b/pcbnew/plugins/altium/altium_parser_pcb.h index f0d74de664..f0bbce33bf 100644 --- a/pcbnew/plugins/altium/altium_parser_pcb.h +++ b/pcbnew/plugins/altium/altium_parser_pcb.h @@ -549,6 +549,7 @@ struct AREGION6 ALTIUM_LAYER layer; uint16_t net; uint16_t component; + uint16_t polygon; uint16_t subpolyindex; uint8_t keepoutrestrictions; uint16_t holecount; @@ -570,6 +571,7 @@ struct AARC6 ALTIUM_LAYER layer; uint16_t net; uint16_t component; + uint16_t polygon; uint16_t subpolyindex; uint8_t keepoutrestrictions; @@ -683,6 +685,7 @@ struct ATRACK6 ALTIUM_LAYER layer; uint16_t net; uint16_t component; + uint16_t polygon; uint16_t subpolyindex; uint8_t keepoutrestrictions; diff --git a/pcbnew/plugins/altium/altium_pcb.cpp b/pcbnew/plugins/altium/altium_pcb.cpp index d5168a16f6..9577570ebf 100644 --- a/pcbnew/plugins/altium/altium_pcb.cpp +++ b/pcbnew/plugins/altium/altium_pcb.cpp @@ -530,6 +530,21 @@ void ALTIUM_PCB::Parse( const ALTIUM_COMPOUND_FILE& altiumPcbFi for( std::pair& zone : m_outer_plane ) zone.second->SetAssignedPriority( 0 ); + // Simplify and fracture zone fills in case we constructed them from tracks (hatched fill) + for( ZONE* zone : m_polygons ) + { + if( !zone ) + continue; + + for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() ) + { + if( !zone->HasFilledPolysForLayer( layer ) ) + continue; + + zone->GetFilledPolysList( layer )->Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE ); + } + } + // Altium doesn't appear to store either the dimension value nor the dimensioned object in // the dimension record. (Yes, there is a REFERENCE0OBJECTID, but it doesn't point to the // dimensioned object.) We attempt to plug this gap by finding a colocated arc or circle @@ -2038,7 +2053,7 @@ void ALTIUM_PCB::ConvertShapeBasedRegions6ToBoardItem( const AREGION6& aElem ) } else if( aElem.kind == ALTIUM_REGION_KIND::COPPER ) { - if( aElem.subpolyindex == ALTIUM_POLYGON_NONE ) + if( aElem.polygon == ALTIUM_POLYGON_NONE ) { for( PCB_LAYER_ID klayer : GetKicadLayersToIterate( aElem.layer ) ) ConvertShapeBasedRegions6ToBoardItemOnLayer( aElem, klayer ); @@ -2101,7 +2116,7 @@ void ALTIUM_PCB::ConvertShapeBasedRegions6ToFootprintItem( FOOTPRINT* aFoot } else if( aElem.kind == ALTIUM_REGION_KIND::COPPER ) { - if( aElem.subpolyindex == ALTIUM_POLYGON_NONE ) + if( aElem.polygon == ALTIUM_POLYGON_NONE ) { for( PCB_LAYER_ID klayer : GetKicadLayersToIterate( aElem.layer ) ) { @@ -2309,28 +2324,22 @@ void ALTIUM_PCB::ParseRegions6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFi ALTIUM_PARSER reader( aAltiumPcbFile, aEntry ); - for( ZONE* zone : m_polygons ) - { - if( zone ) - zone->UnFill(); // just to be sure - } - while( reader.GetRemainingBytes() >= 4 /* TODO: use Header section of file */ ) { checkpoint(); AREGION6 elem( reader, false ); - if( elem.subpolyindex != ALTIUM_POLYGON_NONE ) + if( elem.polygon != ALTIUM_POLYGON_NONE ) { - if( m_polygons.size() <= elem.subpolyindex ) + if( m_polygons.size() <= elem.polygon ) { THROW_IO_ERROR( wxString::Format( "Region stream tries to access polygon id %d " "of %d existing polygons.", - elem.subpolyindex, + elem.polygon, m_polygons.size() ) ); } - ZONE *zone = m_polygons.at( elem.subpolyindex ); + ZONE* zone = m_polygons.at( elem.polygon ); if( zone == nullptr ) { @@ -2440,8 +2449,44 @@ void ALTIUM_PCB::ConvertArcs6ToPcbShape( const AARC6& aElem, PCB_SHAPE* aShape ) void ALTIUM_PCB::ConvertArcs6ToBoardItem( const AARC6& aElem, const int aPrimitiveIndex ) { - if( aElem.is_polygonoutline || aElem.subpolyindex != ALTIUM_POLYGON_NONE ) + if( aElem.polygon != ALTIUM_POLYGON_NONE ) + { + if( m_polygons.size() <= aElem.polygon ) + { + THROW_IO_ERROR( wxString::Format( "Tracks stream tries to access polygon id %d " + "of %d existing polygons.", + aElem.polygon, m_polygons.size() ) ); + } + + ZONE* zone = m_polygons.at( aElem.polygon ); + + if( zone == nullptr ) + { + return; // we know the zone id, but because we do not know the layer we did not + // add it! + } + + PCB_LAYER_ID klayer = GetKicadLayer( aElem.layer ); + + if( klayer == UNDEFINED_LAYER ) + return; // Just skip it for now. Users can fill it themselves. + + SHAPE_POLY_SET* fill = zone->GetFill( klayer ); + + // This is not the actual board item. We can use it to create the polygon for the region + PCB_SHAPE shape( nullptr ); + + ConvertArcs6ToPcbShape( aElem, &shape ); + shape.SetStroke( STROKE_PARAMS( aElem.width, LINE_STYLE::SOLID ) ); + + shape.EDA_SHAPE::TransformShapeToPolygon( *fill, 0, ARC_HIGH_DEF, ERROR_INSIDE ); + // Will be simplified and fractured later + + zone->SetIsFilled( true ); + zone->SetNeedRefill( false ); + return; + } if( aElem.is_keepout || aElem.layer == ALTIUM_LAYER::KEEP_OUT_LAYER || IsAltiumLayerAPlane( aElem.layer ) ) @@ -2482,8 +2527,12 @@ void ALTIUM_PCB::ConvertArcs6ToBoardItem( const AARC6& aElem, const int aPrimiti void ALTIUM_PCB::ConvertArcs6ToFootprintItem( FOOTPRINT* aFootprint, const AARC6& aElem, const int aPrimitiveIndex, const bool aIsBoardImport ) { - if( aElem.is_polygonoutline || aElem.subpolyindex != ALTIUM_POLYGON_NONE ) + if( aElem.polygon != ALTIUM_POLYGON_NONE ) + { + wxFAIL_MSG( wxString::Format( "Altium: Unexpected footprint Arc with polygon id %d", + aElem.polygon ) ); return; + } if( aElem.is_keepout || aElem.layer == ALTIUM_LAYER::KEEP_OUT_LAYER || IsAltiumLayerAPlane( aElem.layer ) ) @@ -3134,8 +3183,43 @@ void ALTIUM_PCB::ParseTracks6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFil void ALTIUM_PCB::ConvertTracks6ToBoardItem( const ATRACK6& aElem, const int aPrimitiveIndex ) { - if( aElem.is_polygonoutline || aElem.subpolyindex != ALTIUM_POLYGON_NONE ) + if( aElem.polygon != ALTIUM_POLYGON_NONE ) + { + if( m_polygons.size() <= aElem.polygon ) + { + THROW_IO_ERROR( wxString::Format( "Tracks stream tries to access polygon id %d " + "of %d existing polygons.", + aElem.polygon, m_polygons.size() ) ); + } + + ZONE* zone = m_polygons.at( aElem.polygon ); + + if( zone == nullptr ) + { + return; // we know the zone id, but because we do not know the layer we did not + // add it! + } + + PCB_LAYER_ID klayer = GetKicadLayer( aElem.layer ); + + if( klayer == UNDEFINED_LAYER ) + return; // Just skip it for now. Users can fill it themselves. + + SHAPE_POLY_SET* fill = zone->GetFill( klayer ); + + PCB_SHAPE shape( nullptr, SHAPE_T::SEGMENT ); + shape.SetStart( aElem.start ); + shape.SetEnd( aElem.end ); + shape.SetStroke( STROKE_PARAMS( aElem.width, LINE_STYLE::SOLID ) ); + + shape.EDA_SHAPE::TransformShapeToPolygon( *fill, 0, ARC_HIGH_DEF, ERROR_INSIDE ); + // Will be simplified and fractured later + + zone->SetIsFilled( true ); + zone->SetNeedRefill( false ); + return; + } if( aElem.is_keepout || aElem.layer == ALTIUM_LAYER::KEEP_OUT_LAYER || IsAltiumLayerAPlane( aElem.layer ) ) @@ -3177,8 +3261,12 @@ void ALTIUM_PCB::ConvertTracks6ToFootprintItem( FOOTPRINT* aFootprint, const ATR const int aPrimitiveIndex, const bool aIsBoardImport ) { - if( aElem.is_polygonoutline || aElem.subpolyindex != ALTIUM_POLYGON_NONE ) + if( aElem.polygon != ALTIUM_POLYGON_NONE ) + { + wxFAIL_MSG( wxString::Format( "Altium: Unexpected footprint Track with polygon id %d", + aElem.polygon ) ); return; + } if( aElem.is_keepout || aElem.layer == ALTIUM_LAYER::KEEP_OUT_LAYER || IsAltiumLayerAPlane( aElem.layer ) )