Fix DXF import corruption with large coordinates
The overflow check for auto-offsetting imported graphics did not account for the IU conversion factor, causing DXF files with coordinates around 2300mm to exhibit visual glitches. The check compared mm values directly against INT32_MAX, but after IU conversion (multiply by 1e6 for PCB), these values exceed the integer limit. Fixes https://gitlab.com/kicad/code/kicad/-/issues/9681
This commit is contained in:
@@ -131,10 +131,12 @@ void GRAPHICS_IMPORTER_BUFFER::ImportTo( GRAPHICS_IMPORTER& aImporter )
|
||||
// the graphics in the KiCad drawing area.
|
||||
else if( aImporter.GetImportOffsetMM() == VECTOR2D( 0, 0 ) )
|
||||
{
|
||||
if( boundingBox.GetRight() > std::numeric_limits<int>::max()
|
||||
|| boundingBox.GetBottom() > std::numeric_limits<int>::max()
|
||||
|| boundingBox.GetLeft() < std::numeric_limits<int>::min()
|
||||
|| boundingBox.GetTop() < std::numeric_limits<int>::min() )
|
||||
double iuFactor = aImporter.GetMillimeterToIuFactor();
|
||||
|
||||
if( boundingBox.GetRight() * iuFactor > std::numeric_limits<int>::max()
|
||||
|| boundingBox.GetBottom() * iuFactor > std::numeric_limits<int>::max()
|
||||
|| boundingBox.GetLeft() * iuFactor < std::numeric_limits<int>::min()
|
||||
|| boundingBox.GetTop() * iuFactor < std::numeric_limits<int>::min() )
|
||||
{
|
||||
VECTOR2D offset = boundingBox.GetOrigin();
|
||||
aImporter.SetImportOffsetMM( -offset );
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
0
|
||||
SECTION
|
||||
2
|
||||
HEADER
|
||||
9
|
||||
$ACADVER
|
||||
1
|
||||
AC1018
|
||||
9
|
||||
$INSUNITS
|
||||
70
|
||||
4
|
||||
9
|
||||
$EXTMIN
|
||||
10
|
||||
2300.0
|
||||
20
|
||||
1400.0
|
||||
30
|
||||
0.0
|
||||
9
|
||||
$EXTMAX
|
||||
10
|
||||
2350.0
|
||||
20
|
||||
1450.0
|
||||
30
|
||||
0.0
|
||||
0
|
||||
ENDSEC
|
||||
0
|
||||
SECTION
|
||||
2
|
||||
ENTITIES
|
||||
0
|
||||
LINE
|
||||
8
|
||||
0
|
||||
10
|
||||
2300.0
|
||||
20
|
||||
1400.0
|
||||
30
|
||||
0.0
|
||||
11
|
||||
2350.0
|
||||
21
|
||||
1450.0
|
||||
31
|
||||
0.0
|
||||
0
|
||||
ARC
|
||||
8
|
||||
0
|
||||
10
|
||||
2325.0
|
||||
20
|
||||
1425.0
|
||||
30
|
||||
0.0
|
||||
40
|
||||
10.0
|
||||
50
|
||||
0.0
|
||||
51
|
||||
90.0
|
||||
0
|
||||
ENDSEC
|
||||
0
|
||||
EOF
|
||||
@@ -92,6 +92,9 @@ set( QA_COMMON_SRCS
|
||||
# GAL tests
|
||||
test_gal_xor_mode.cpp
|
||||
|
||||
# Graphics import tests
|
||||
test_graphics_importer_buffer.cpp
|
||||
|
||||
# Project template tests (source included directly since it's from kicad executable)
|
||||
test_project_template.cpp
|
||||
${CMAKE_SOURCE_DIR}/kicad/project_template.cpp
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright The 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
|
||||
*/
|
||||
|
||||
#include <qa_utils/wx_utils/unit_test_utils.h>
|
||||
|
||||
#include <eda_item.h>
|
||||
#include <import_gfx/graphics_importer_buffer.h>
|
||||
#include <base_units.h>
|
||||
#include <limits>
|
||||
|
||||
|
||||
class TEST_GRAPHICS_IMPORTER : public GRAPHICS_IMPORTER
|
||||
{
|
||||
public:
|
||||
TEST_GRAPHICS_IMPORTER() : GRAPHICS_IMPORTER()
|
||||
{
|
||||
m_millimeterToIu = PCB_IU_PER_MM;
|
||||
}
|
||||
|
||||
void AddLine( const VECTOR2D& aStart, const VECTOR2D& aEnd,
|
||||
const IMPORTED_STROKE& aStroke ) override
|
||||
{
|
||||
m_lines.push_back( { aStart, aEnd } );
|
||||
}
|
||||
|
||||
void AddCircle( const VECTOR2D& aCenter, double aRadius, const IMPORTED_STROKE& aStroke,
|
||||
bool aFilled, const COLOR4D& aFillColor ) override {}
|
||||
|
||||
void AddArc( const VECTOR2D& aCenter, const VECTOR2D& aStart, const EDA_ANGLE& aAngle,
|
||||
const IMPORTED_STROKE& aStroke ) override {}
|
||||
|
||||
void AddPolygon( const std::vector<VECTOR2D>& aVertices, const IMPORTED_STROKE& aStroke,
|
||||
bool aFilled, const COLOR4D& aFillColor ) override {}
|
||||
|
||||
void AddText( const VECTOR2D& aOrigin, const wxString& aText, double aHeight, double aWidth,
|
||||
double aThickness, double aOrientation, GR_TEXT_H_ALIGN_T aHJustify,
|
||||
GR_TEXT_V_ALIGN_T aVJustify, const COLOR4D& aColor ) override {}
|
||||
|
||||
void AddSpline( const VECTOR2D& aStart, const VECTOR2D& aBezierControl1,
|
||||
const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
|
||||
const IMPORTED_STROKE& aStroke ) override {}
|
||||
|
||||
std::vector<std::pair<VECTOR2D, VECTOR2D>> m_lines;
|
||||
};
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE( GraphicsImporterBuffer )
|
||||
|
||||
|
||||
/**
|
||||
* Test that large coordinates that would overflow when converted to internal units
|
||||
* are automatically offset to fit within the valid coordinate range.
|
||||
*
|
||||
* This tests the fix for GitLab issue #9681 where DXF files with large coordinates
|
||||
* (e.g., around 2300mm which exceeds INT_MAX/1e6 ~= 2147mm) caused visual corruption.
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE( LargeCoordinatesAutoOffset )
|
||||
{
|
||||
GRAPHICS_IMPORTER_BUFFER buffer;
|
||||
TEST_GRAPHICS_IMPORTER importer;
|
||||
|
||||
// Add a line with coordinates that would overflow INT32 when converted to IU
|
||||
// 2300mm * 1e6 IU/mm = 2.3e9 > INT32_MAX (2.147e9)
|
||||
VECTOR2D start( 2300.0, 1400.0 );
|
||||
VECTOR2D end( 2350.0, 1450.0 );
|
||||
|
||||
IMPORTED_STROKE stroke( 0.1 );
|
||||
buffer.AddLine( start, end, stroke );
|
||||
|
||||
// Import with no offset set (default is 0,0)
|
||||
BOOST_CHECK( importer.GetImportOffsetMM() == VECTOR2D( 0, 0 ) );
|
||||
|
||||
buffer.ImportTo( importer );
|
||||
|
||||
// After import, the offset should have been automatically adjusted
|
||||
// to move the coordinates into the valid range
|
||||
VECTOR2D offset = importer.GetImportOffsetMM();
|
||||
|
||||
// The offset should be negative of the bounding box origin to bring coordinates near zero
|
||||
BOOST_CHECK_MESSAGE( offset.x < 0, "X offset should be negative to shift large coords down" );
|
||||
|
||||
// Verify the resulting coordinates are within valid IU range
|
||||
if( !importer.m_lines.empty() )
|
||||
{
|
||||
VECTOR2D importedStart = importer.m_lines[0].first;
|
||||
VECTOR2D importedEnd = importer.m_lines[0].second;
|
||||
|
||||
// After offset and scale, coordinates should be manageable
|
||||
double maxCoord = static_cast<double>( std::numeric_limits<int>::max() )
|
||||
/ importer.GetMillimeterToIuFactor();
|
||||
|
||||
BOOST_CHECK_MESSAGE( ( importedStart.x + offset.x ) < maxCoord,
|
||||
"Imported X coord should be within valid range" );
|
||||
BOOST_CHECK_MESSAGE( ( importedStart.y + offset.y ) < maxCoord,
|
||||
"Imported Y coord should be within valid range" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test that normal coordinates (within valid range) are not modified.
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE( NormalCoordinatesNoOffset )
|
||||
{
|
||||
GRAPHICS_IMPORTER_BUFFER buffer;
|
||||
TEST_GRAPHICS_IMPORTER importer;
|
||||
|
||||
// Add a line with normal coordinates that fit within the valid range
|
||||
// 100mm * 1e6 IU/mm = 1e8 << INT32_MAX
|
||||
VECTOR2D start( 100.0, 100.0 );
|
||||
VECTOR2D end( 200.0, 200.0 );
|
||||
|
||||
IMPORTED_STROKE stroke( 0.1 );
|
||||
buffer.AddLine( start, end, stroke );
|
||||
|
||||
buffer.ImportTo( importer );
|
||||
|
||||
// Offset should remain at zero since coordinates are valid
|
||||
VECTOR2D offset = importer.GetImportOffsetMM();
|
||||
BOOST_CHECK_MESSAGE( offset == VECTOR2D( 0, 0 ),
|
||||
"Normal coordinates should not trigger auto-offset" );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
Reference in New Issue
Block a user