Add conversion from CADSTAR SHAPE to SHAPE_POLY_SET

This commit is contained in:
Roberto Fernandez Bautista 2021-11-29 21:33:07 +01:00
parent 7e01816b73
commit ee6e86d1db
4 changed files with 254 additions and 4 deletions

View File

@ -27,6 +27,7 @@
#include <wx/xml/xml.h>
#include <dsnlexer.h>
#include <geometry/shape_poly_set.h>
#include <plugins/cadstar/cadstar_archive_parser.h>
#include <eda_item.h>
#include <eda_text.h>
@ -481,6 +482,45 @@ void CADSTAR_ARCHIVE_PARSER::VERTEX::Parse( XNODE* aNode, PARSER_CONTEXT* aConte
}
void CADSTAR_ARCHIVE_PARSER::VERTEX::AppendToChain( SHAPE_LINE_CHAIN* aChainToAppendTo,
const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback ) const
{
VECTOR2I endPoint = aCadstarToKicadPointCallback( End );
if( Type == VERTEX_TYPE::POINT )
{
aChainToAppendTo->Append( endPoint );
return;
}
wxCHECK_MSG( aChainToAppendTo->PointCount() > 0, /*void*/,
"Can't append an arc to vertex to an empty chain" );
VECTOR2I startPoint = aChainToAppendTo->GetPoint( -1 );
VECTOR2I centerPoint;
if( Type == VERTEX_TYPE::ANTICLOCKWISE_SEMICIRCLE || Type == VERTEX_TYPE::CLOCKWISE_SEMICIRCLE )
centerPoint = ( startPoint / 2 ) + ( endPoint / 2 );
else
centerPoint = aCadstarToKicadPointCallback( Center );
bool clockwise = Type == VERTEX_TYPE::CLOCKWISE_ARC
|| Type == VERTEX_TYPE::CLOCKWISE_SEMICIRCLE;
// A bit of a hack to figure out if we need to invert clockwise due to the transform
VECTOR2I transform = aCadstarToKicadPointCallback( { 500, 500 } )
- aCadstarToKicadPointCallback( { 0, 0 } );
if( ( transform.x > 0 && transform.y < 0 ) || ( transform.x < 0 && transform.y > 0 ) )
clockwise = !clockwise;
SHAPE_ARC arc;
arc.ConstructFromStartEndCenter( startPoint, endPoint, centerPoint, clockwise );
aChainToAppendTo->Append( arc );
}
void CADSTAR_ARCHIVE_PARSER::CUTOUT::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
{
wxASSERT( aNode->GetName() == wxT( "CUTOUT" ) );
@ -545,6 +585,45 @@ void CADSTAR_ARCHIVE_PARSER::SHAPE::Parse( XNODE* aNode, PARSER_CONTEXT* aContex
}
}
SHAPE_LINE_CHAIN CADSTAR_ARCHIVE_PARSER::SHAPE::OutlineAsChain(
const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback ) const
{
SHAPE_LINE_CHAIN outline;
for( const auto& vertex : Vertices )
vertex.AppendToChain( &outline, aCadstarToKicadPointCallback );
if( Type != SHAPE_TYPE::OPENSHAPE )
outline.SetClosed( true );
return outline;
}
SHAPE_POLY_SET CADSTAR_ARCHIVE_PARSER::SHAPE::ConvertToPolySet(
const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback ) const
{
SHAPE_POLY_SET polyset;
wxCHECK( Type != SHAPE_TYPE::OPENSHAPE, polyset ); // We shouldn't convert openshapes to polyset!
polyset.AddOutline( OutlineAsChain( aCadstarToKicadPointCallback) );
for( const auto& cutout : Cutouts )
{
SHAPE_LINE_CHAIN hole;
for( const auto& cutoutVertex : cutout.Vertices )
cutoutVertex.AppendToChain( &hole, aCadstarToKicadPointCallback );
hole.SetClosed( true );
polyset.AddHole( hole );
}
return polyset;
}
CADSTAR_ARCHIVE_PARSER::UNITS CADSTAR_ARCHIVE_PARSER::ParseUnits( XNODE* aNode )
{

View File

@ -34,6 +34,8 @@
#include <vector>
#include <xnode.h>
#include <math/vector2d.h>
// THROW_IO_ERROR definitions to ensure consistent wording is used in the error messages
#define THROW_MISSING_NODE_IO_ERROR( nodename, location ) \
@ -79,6 +81,8 @@
class EDA_TEXT;
class wxXmlAttribute;
class PROGRESS_REPORTER;
class SHAPE_LINE_CHAIN;
class SHAPE_POLY_SET;
/**
* @brief Helper functions and common structures for CADSTAR PCB and Schematic archive files.
@ -396,9 +400,8 @@ public:
*/
struct POINT : wxPoint, PARSER
{
POINT() : wxPoint( UNDEFINED_VALUE, UNDEFINED_VALUE )
{
}
POINT() : wxPoint( UNDEFINED_VALUE, UNDEFINED_VALUE ) {}
POINT( int aX, int aY ) : wxPoint( aX, aY ) {}
void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
};
@ -413,6 +416,12 @@ public:
};
struct TRANSFORM
{
virtual wxPoint Apply( POINT aCadstarPoint ) = 0;
};
enum class VERTEX_TYPE
{
POINT,
@ -428,12 +437,19 @@ public:
*/
struct VERTEX : PARSER
{
VERTEX( VERTEX_TYPE aType = VERTEX_TYPE::POINT, POINT aEnd = POINT(), POINT aCenter = POINT() ) :
Type( aType ), End( aEnd ), Center( aCenter )
{}
VERTEX_TYPE Type;
POINT Center;
POINT End;
POINT Center;
static bool IsVertex( XNODE* aNode );
void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
void AppendToChain( SHAPE_LINE_CHAIN* aChainToAppendTo,
const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback ) const;
};
/**
@ -465,6 +481,12 @@ public:
static bool IsShape( XNODE* aNode );
void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
SHAPE_LINE_CHAIN OutlineAsChain( const std::function<VECTOR2I( const VECTOR2I& )>
aCadstarToKicadPointCallback ) const;
SHAPE_POLY_SET ConvertToPolySet( const std::function<VECTOR2I( const VECTOR2I& )>
aCadstarToKicadPointCallback ) const;
};

View File

@ -51,6 +51,8 @@ set( QA_COMMON_SRCS
plugins/altium/test_altium_parser.cpp
plugins/altium/test_altium_parser_utils.cpp
plugins/cadstar/test_cadstar_archive_parser.cpp
view/test_zoom_controller.cpp
)

View File

@ -0,0 +1,147 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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
* 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
*/
/**
* @file test_cadstar_archive_parser.cpp
* Test suite for #CADSTAR_ARCHIVE_PARSER
*/
#include <qa_utils/wx_utils/unit_test_utils.h>
#include <common/plugins/cadstar/cadstar_archive_parser.h>
#include <qa_utils/geometry/geometry.h> // For KI_TEST::IsVecWithinTol
#include <geometry/shape_line_chain.h>
#include <geometry/shape_arc.h> // For SHAPE_ARC::DefaultAccuracyForPCB()
BOOST_AUTO_TEST_SUITE( CadstartArchiveParser )
struct VERTEX_APPEND_CASE
{
std::string m_CaseName;
CADSTAR_ARCHIVE_PARSER::VERTEX m_VertexToAppend;
BOX2I m_ExpBBox;
int m_ExpBBoxError;
};
std::function<wxPoint( const wxPoint& )> m_CadstarToKicadPointCallback;
using vt=CADSTAR_ARCHIVE_PARSER::VERTEX_TYPE;
static const std::vector<VERTEX_APPEND_CASE> appendToChainCases
{
{
"Append a point on x",
{ vt::POINT, { 500000, 0 } },
{ /* BBOX Position: */ { 0, 0 }, /* Size:*/ { 500000, 0 } },
0
},
{
"Append a point on y",
{ vt::POINT, { 0, 500000 } },
{ /* BBOX Position: */ { 0, 0 }, /* Size:*/ { 0, 500000 } },
0
},
{
"Append a Semicircle (clockwise)",
{ vt::CLOCKWISE_SEMICIRCLE, { 500000, 0 } },
{ /* BBOX Position: */ { 0, 0 }, /* Size: */ { 500000, 250000 } },
int( SHAPE_ARC::DefaultAccuracyForPCB() ) // acceptable error when converting to line segments
},
{
"Append a Semicircle (anticlockwise)",
{ vt::ANTICLOCKWISE_SEMICIRCLE, { 500000, 0 } },
{ /* BBOX Position: */ { 0, -250000 }, /* Size: */ { 500000, 250000 } },
int( SHAPE_ARC::DefaultAccuracyForPCB() ) // acceptable error when converting to line segments
},
{
"Append a 90 degree Arc (clockwise)",
{ vt::CLOCKWISE_ARC, { 250000, 250000 }, { 250000, 0 } },
{ /* BBOX Position: */ { 0, 0 }, /* Size: */ { 250000, 250000 } },
int( SHAPE_ARC::DefaultAccuracyForPCB() ) // acceptable error when converting to line segments
},
{
"Append a 90 degree Arc (anticlockwise)",
{ vt::ANTICLOCKWISE_ARC, { 250000, -250000 }, { 250000, 0 } },
{ /* BBOX Position: */ { 0, -250000 }, /* Size: */ { 250000, 250000 } },
int( SHAPE_ARC::DefaultAccuracyForPCB() ) // acceptable error when converting to line segments
},
};
BOOST_AUTO_TEST_CASE( AppendToChain )
{
static const std::vector<VECTOR2D> coordinateMultipliers =
{
{ 0.1, 0.1 },
{ 0.1, -0.1 }, // y inversion
{ 1, 1 },
{ 1, -1 }, // y inversion
{ 10, 10 },
{ 10, -10 } // y inversion
};
for( const auto& c : appendToChainCases )
{
BOOST_TEST_INFO_SCOPE( c.m_CaseName );
for( const VECTOR2D& mult : coordinateMultipliers )
{
BOOST_TEST_INFO_SCOPE( "Applied scaling x=" << mult.x << " y=" << mult.y );
SHAPE_LINE_CHAIN chain( { 0, 0 } ); // starting chain contains a point at 0,0
auto transformCoord =
[&]( const VECTOR2I& aPt ) -> VECTOR2I
{
int x = double( aPt.x ) * mult.x;
int y = double( aPt.y ) * mult.y;
return { x, y };
};
c.m_VertexToAppend.AppendToChain( &chain, transformCoord );
BOX2I expBoxTransformed;
expBoxTransformed.SetOrigin( transformCoord( c.m_ExpBBox.GetPosition() ) );
expBoxTransformed.SetSize( transformCoord( c.m_ExpBBox.GetSize() ) );
expBoxTransformed.Normalize();
BOOST_CHECK_PREDICATE(
KI_TEST::IsVecWithinTol<VECTOR2I>,
( chain.BBox().GetPosition() )( expBoxTransformed.GetPosition() ) ( c.m_ExpBBoxError ) );
BOOST_CHECK_PREDICATE(
KI_TEST::IsVecWithinTol<VECTOR2I>,
( chain.BBox().GetSize() )( expBoxTransformed.GetSize() ) ( c.m_ExpBBoxError ) );
}
}
}
BOOST_AUTO_TEST_SUITE_END()