mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 02:03:12 +02:00
The last segment of a track could be removed when the iterator does not correctly loop. Keeping the ll within bounds and checking for equivalency instead of comparison works for last point
1089 lines
51 KiB
C++
1089 lines
51 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2019-2021 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 <geometry/shape_arc.h>
|
|
#include <geometry/shape_line_chain.h>
|
|
#include <trigo.h>
|
|
|
|
#include <qa_utils/geometry/geometry.h>
|
|
#include <qa_utils/numeric.h>
|
|
#include <qa_utils/wx_utils/unit_test_utils.h>
|
|
|
|
#include "geom_test_utils.h"
|
|
|
|
/**
|
|
* NOTE: Collision of SHAPE_LINE_CHAIN with arcs is tested in test_shape_arc.cpp
|
|
*/
|
|
|
|
struct SLC_CASES
|
|
{
|
|
SHAPE_LINE_CHAIN Circle1Arc;
|
|
SHAPE_LINE_CHAIN Circle2Arcs;
|
|
SHAPE_LINE_CHAIN ArcsCoincident;
|
|
SHAPE_LINE_CHAIN ArcsCoincidentClosed;
|
|
SHAPE_LINE_CHAIN ArcsIndependent;
|
|
SHAPE_LINE_CHAIN DuplicateArcs;
|
|
SHAPE_LINE_CHAIN ArcsAndSegMixed;
|
|
SHAPE_LINE_CHAIN ArcAndPoint;
|
|
SHAPE_LINE_CHAIN SegAndArcCoincident;
|
|
SHAPE_LINE_CHAIN EmptyChain;
|
|
SHAPE_LINE_CHAIN OnePoint;
|
|
SHAPE_LINE_CHAIN TwoPoints;
|
|
SHAPE_LINE_CHAIN ThreePoints;
|
|
|
|
SHAPE_ARC ArcCircle; ///< Full Circle arc
|
|
SHAPE_ARC Arc0a; ///< First half of a circle
|
|
SHAPE_ARC Arc0b; ///< Second half of a circle
|
|
SHAPE_ARC Arc1; ///< start coincident with Arc0a end
|
|
SHAPE_ARC Arc2; ///< Independent arc
|
|
SHAPE_ARC Arc3; ///< Arc with angle >180
|
|
|
|
SLC_CASES()
|
|
{
|
|
ArcCircle = SHAPE_ARC( VECTOR2I( 183450000, 128360000 ),
|
|
VECTOR2I( 183850000, 128360000 ),
|
|
VECTOR2I( 183450000, 128360000 ), 0 );
|
|
|
|
Arc0a = SHAPE_ARC( VECTOR2I( 183450000, 128360000 ),
|
|
VECTOR2I( 183650000, 128560000 ),
|
|
VECTOR2I( 183850000, 128360000 ), 0 );
|
|
|
|
Arc0b = SHAPE_ARC( VECTOR2I( 183850000, 128360000 ),
|
|
VECTOR2I( 183650000, 128160000 ),
|
|
VECTOR2I( 183450000, 128360000 ), 0 );
|
|
|
|
Arc1 = SHAPE_ARC( VECTOR2I( 183850000, 128360000 ),
|
|
VECTOR2I( 183638550, 128640305 ),
|
|
VECTOR2I( 183500000, 129204974 ), 0 );
|
|
|
|
Arc2 = SHAPE_ARC( VECTOR2I( 283450000, 228360000 ),
|
|
VECTOR2I( 283650000, 228560000 ),
|
|
VECTOR2I( 283850000, 228360000 ), 0 );
|
|
|
|
Arc3 = SHAPE_ARC( VECTOR2I( 0, 0 ),
|
|
VECTOR2I( 24142136, 10000000 ),
|
|
VECTOR2I( 0, 20000000 ), 0 );
|
|
|
|
Circle1Arc.Append( ArcCircle );
|
|
Circle1Arc.SetClosed( true );
|
|
|
|
Circle2Arcs.Append( Arc0a );
|
|
Circle2Arcs.Append( Arc0b );
|
|
Circle2Arcs.SetClosed( true );
|
|
|
|
ArcsCoincident.Append( Arc0a );
|
|
ArcsCoincident.Append( Arc1 );
|
|
|
|
ArcsCoincidentClosed=ArcsCoincident;
|
|
ArcsCoincidentClosed.SetClosed( true );
|
|
|
|
ArcsIndependent.Append( Arc0a );
|
|
ArcsIndependent.Append( Arc2 );
|
|
|
|
DuplicateArcs=ArcsCoincident;
|
|
DuplicateArcs.Append( Arc1 ); //should add a segment between end of the chain and new copy of the arc
|
|
|
|
ArcAndPoint.Append( Arc0a );
|
|
ArcAndPoint.Append( VECTOR2I( 233450000, 228360000 ) );
|
|
|
|
ArcsAndSegMixed = ArcAndPoint;
|
|
ArcsAndSegMixed.Append( Arc2 );
|
|
|
|
OnePoint.Append( VECTOR2I( 233450000, 228360000 ) );
|
|
|
|
TwoPoints.Append( VECTOR2I( 233450000, 228360000 ) );
|
|
TwoPoints.Append( VECTOR2I( 263450000, 258360000 ) );
|
|
|
|
ThreePoints = TwoPoints;
|
|
ThreePoints.Append( VECTOR2I( 263450000, 308360000 ) );
|
|
|
|
SegAndArcCoincident.Append( VECTOR2I( 0, 20000000 ) );
|
|
SegAndArcCoincident.Append( Arc3 );
|
|
}
|
|
};
|
|
|
|
|
|
BOOST_FIXTURE_TEST_SUITE( TestShapeLineChain, SLC_CASES )
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE( ClipperConstructorCase1 )
|
|
{
|
|
// Case of an arc followed by a segment
|
|
// The clipper path is not in order (on purpose), to simulate the typical return from clipper
|
|
|
|
ClipperLib::Path pathClipper1 = {
|
|
{ { 125663951, 120099260, 24 }, { 125388111, 120170850, 25 }, { 125124975, 120280270, 26 },
|
|
{ 124879705, 120425376, 27 }, { 124657110, 120603322, 28 }, { 124461556, 120810617, 29 },
|
|
{ 124296876, 121043198, 30 }, { 124166301, 121296503, 31 }, { 124072391, 121565564, 32 },
|
|
{ 124016988, 121845106, 33 }, { 124001177, 122129646, 34 }, { 124025270, 122413605, 35 },
|
|
{ 124088794, 122691414, 36 }, { 124190502, 122957625, 37 }, { 124328401, 123207018, 38 },
|
|
{ 124499787, 123434703, 39 }, { 124598846, 123537154, 40 }, { 127171000, 123786000, 4 },
|
|
{ 127287862, 123704439, 5 }, { 127499716, 123513831, 6 }, { 127682866, 123295498, 7 },
|
|
{ 127833720, 123053722, 8 }, { 127949321, 122793242, 9 }, { 128027402, 122519168, 10 },
|
|
{ 128066430, 122236874, 11 }, { 128065642, 121951896, 12 }, { 128025053, 121669823, 13 },
|
|
{ 127945457, 121396185, 14 }, { 127828417, 121136349, 15 }, { 127676227, 120895410, 16 },
|
|
{ 127491873, 120678094, 17 }, { 127278968, 120488661, 18 }, { 127041689, 120330827, 19 },
|
|
{ 126784688, 120207687, 20 }, { 126513005, 120121655, 21 }, { 126231968, 120074419, 22 },
|
|
{ 125947087, 120066905, 23 } }
|
|
};
|
|
Clipper2Lib::Path64 pathClipper2 = {
|
|
{ { 125663951, 120099260, 24 }, { 125388111, 120170850, 25 }, { 125124975, 120280270, 26 },
|
|
{ 124879705, 120425376, 27 }, { 124657110, 120603322, 28 }, { 124461556, 120810617, 29 },
|
|
{ 124296876, 121043198, 30 }, { 124166301, 121296503, 31 }, { 124072391, 121565564, 32 },
|
|
{ 124016988, 121845106, 33 }, { 124001177, 122129646, 34 }, { 124025270, 122413605, 35 },
|
|
{ 124088794, 122691414, 36 }, { 124190502, 122957625, 37 }, { 124328401, 123207018, 38 },
|
|
{ 124499787, 123434703, 39 }, { 124598846, 123537154, 40 }, { 127171000, 123786000, 4 },
|
|
{ 127287862, 123704439, 5 }, { 127499716, 123513831, 6 }, { 127682866, 123295498, 7 },
|
|
{ 127833720, 123053722, 8 }, { 127949321, 122793242, 9 }, { 128027402, 122519168, 10 },
|
|
{ 128066430, 122236874, 11 }, { 128065642, 121951896, 12 }, { 128025053, 121669823, 13 },
|
|
{ 127945457, 121396185, 14 }, { 127828417, 121136349, 15 }, { 127676227, 120895410, 16 },
|
|
{ 127491873, 120678094, 17 }, { 127278968, 120488661, 18 }, { 127041689, 120330827, 19 },
|
|
{ 126784688, 120207687, 20 }, { 126513005, 120121655, 21 }, { 126231968, 120074419, 22 },
|
|
{ 125947087, 120066905, 23 } }
|
|
};
|
|
|
|
std::vector<CLIPPER_Z_VALUE> z_values = {
|
|
{ { -1, -1 }, 0 }, { { -1, -1 }, 0 }, { { -1, -1 }, 0 }, { { -1, -1 }, 0 },
|
|
{ { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
|
|
{ { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
|
|
{ { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
|
|
{ { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
|
|
{ { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
|
|
{ { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
|
|
{ { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
|
|
{ { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
|
|
{ { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 }, { { 0, -1 }, 0 },
|
|
{ { 0, -1 }, 0 }
|
|
};
|
|
|
|
std::vector<SHAPE_ARC> arcs = {
|
|
SHAPE_ARC( { 127171000, 123786000 }, { 126231718, 120077003 }, { 124598846, 123537154 }, 0 )
|
|
};
|
|
|
|
SHAPE_LINE_CHAIN clipper1chain( pathClipper1, z_values, arcs );
|
|
SHAPE_LINE_CHAIN clipper2chain( pathClipper2, z_values, arcs );
|
|
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( clipper1chain ) );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( clipper2chain ) );
|
|
|
|
BOOST_CHECK_EQUAL( clipper1chain.PointCount(), 37 );
|
|
BOOST_CHECK_EQUAL( clipper2chain.PointCount(), 37 );
|
|
|
|
BOOST_CHECK_EQUAL( clipper1chain.ArcCount(), 1 );
|
|
BOOST_CHECK_EQUAL( clipper2chain.ArcCount(), 1 );
|
|
|
|
BOOST_CHECK_EQUAL( clipper1chain.ShapeCount(), 2 );
|
|
BOOST_CHECK_EQUAL( clipper2chain.ShapeCount(), 2 );
|
|
|
|
BOOST_CHECK_EQUAL( clipper1chain.IsClosed(), true );
|
|
BOOST_CHECK_EQUAL( clipper2chain.IsClosed(), true );
|
|
}
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE( ArcToPolyline )
|
|
{
|
|
SHAPE_LINE_CHAIN base_chain( { VECTOR2I( 0, 0 ), VECTOR2I( 0, 1000 ), VECTOR2I( 1000, 0 ) } );
|
|
|
|
SHAPE_LINE_CHAIN chain_insert( {
|
|
VECTOR2I( 0, 1500 ),
|
|
VECTOR2I( 1500, 1500 ),
|
|
VECTOR2I( 1500, 0 ),
|
|
} );
|
|
|
|
SHAPE_LINE_CHAIN arc_insert1( SHAPE_ARC( VECTOR2I( 0, -100 ), VECTOR2I( 0, -200 ), ANGLE_180 ) );
|
|
|
|
SHAPE_LINE_CHAIN arc_insert2( SHAPE_ARC( VECTOR2I( 0, 500 ), VECTOR2I( 0, 400 ), ANGLE_180 ) );
|
|
|
|
BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
|
|
BOOST_CHECK_EQUAL( arc_insert1.CShapes().size(), arc_insert1.CPoints().size() );
|
|
BOOST_CHECK_EQUAL( arc_insert2.CShapes().size(), arc_insert2.CPoints().size() );
|
|
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( arc_insert1 ) );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( arc_insert2 ) );
|
|
|
|
base_chain.Insert( 0, SHAPE_ARC( VECTOR2I( 0, -100 ), VECTOR2I( 0, -200 ), ANGLE_180 ) );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
|
|
BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
|
|
|
|
base_chain.Replace( 0, 2, chain_insert );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
|
|
BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
|
|
}
|
|
|
|
|
|
// Similar test to above but with larger coordinates, so we have more than one point per arc
|
|
BOOST_AUTO_TEST_CASE( ArcToPolylineLargeCoords )
|
|
{
|
|
SHAPE_LINE_CHAIN base_chain( { VECTOR2I( 0, 0 ), VECTOR2I( 0, 100000 ), VECTOR2I( 100000, 0 ) } );
|
|
|
|
SHAPE_LINE_CHAIN chain_insert( {
|
|
VECTOR2I( 0, 1500000 ),
|
|
VECTOR2I( 1500000, 1500000 ),
|
|
VECTOR2I( 1500000, 0 ),
|
|
} );
|
|
|
|
base_chain.Append( SHAPE_ARC( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 100000 ), ANGLE_180 ) );
|
|
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
|
|
BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 );
|
|
|
|
base_chain.Insert( 9, VECTOR2I( 250000, 0 ) );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
|
|
BOOST_CHECK_EQUAL( base_chain.PointCount(), 12 );
|
|
BOOST_CHECK_EQUAL( base_chain.ArcCount(), 2 ); // Should have two arcs after the split
|
|
|
|
base_chain.Replace( 5, 6, chain_insert );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
|
|
BOOST_CHECK_EQUAL( base_chain.PointCount(), 13 ); // Adding 3 points, removing 2
|
|
BOOST_CHECK_EQUAL( base_chain.ArcCount(), 3 ); // Should have three arcs after the split
|
|
|
|
base_chain.Replace( 4, 6, VECTOR2I( 550000, 0 ) );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
|
|
BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 ); // Adding 1 point, removing 3
|
|
BOOST_CHECK_EQUAL( base_chain.ArcCount(), 3 ); // Should still have three arcs
|
|
|
|
// Test ClearArcs
|
|
base_chain.SetClosed( true );
|
|
double areaPriorToArcRemoval = base_chain.Area();
|
|
base_chain.ClearArcs();
|
|
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( base_chain ) );
|
|
BOOST_CHECK_EQUAL( base_chain.CPoints().size(), base_chain.CShapes().size() );
|
|
BOOST_CHECK_EQUAL( base_chain.PointCount(), 11 ); // We should have the same number of points
|
|
BOOST_CHECK_EQUAL( base_chain.ArcCount(), 0 ); // All arcs should have been removed
|
|
BOOST_CHECK_EQUAL( base_chain.Area(), areaPriorToArcRemoval ); // Area should not have changed
|
|
}
|
|
|
|
// Test that duplicate point gets removed when line is set to be closed and added where required
|
|
BOOST_AUTO_TEST_CASE( SetClosedDuplicatePoint )
|
|
{
|
|
// Test from issue #9843
|
|
SHAPE_LINE_CHAIN chain;
|
|
|
|
chain.Append(
|
|
SHAPE_ARC( { -859598, 2559876 }, { -1632771, 1022403 }, { -3170244, 249230 }, 0 ) );
|
|
|
|
chain.Append(
|
|
SHAPE_ARC( { -3170244, -1657832 }, { -292804, -317564 }, { 1047464, 2559876 }, 0 ) );
|
|
|
|
chain.Append( VECTOR2I( -859598, 2559876 ) ); // add point that is equal to first arc start
|
|
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 31 );
|
|
|
|
// CLOSED CHAIN
|
|
chain.SetClosed( true );
|
|
BOOST_CHECK_EQUAL( chain.CPoints().size(), chain.CShapes().size() );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 30 ); // (-1) should have removed coincident points
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
|
|
// Special case: arc wrapping around to start (e.g. circle)
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( Circle2Arcs ) );
|
|
BOOST_CHECK_EQUAL( Circle2Arcs.IsClosed(), true );
|
|
BOOST_CHECK_EQUAL( Circle2Arcs.PointCount(), 16 );
|
|
BOOST_CHECK_EQUAL( Circle2Arcs.IsArcSegment( 15 ), true );
|
|
BOOST_CHECK_EQUAL( Circle2Arcs.ShapeCount(), 2 );
|
|
Circle2Arcs.SetClosed( false );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( Circle2Arcs ) );
|
|
BOOST_CHECK_EQUAL( Circle2Arcs.IsClosed(), false );
|
|
BOOST_CHECK_EQUAL( Circle2Arcs.PointCount(), 17 );
|
|
BOOST_CHECK_EQUAL( Circle2Arcs.IsArcSegment( 15 ), true );
|
|
BOOST_CHECK_EQUAL( Circle2Arcs.IsArcSegment( 16 ), false ); // last point doesn't join up
|
|
}
|
|
|
|
struct CLOSE_TOGGLE_SHAPE_CASE
|
|
{
|
|
std::string m_ctx_name;
|
|
SHAPE_LINE_CHAIN m_chain;
|
|
bool m_closed;
|
|
int m_shape_count;
|
|
int m_point_count;
|
|
int m_expected_shape_count;
|
|
int m_expected_point_count;
|
|
};
|
|
|
|
static const std::vector<CLOSE_TOGGLE_SHAPE_CASE> close_toggle_shape_cases =
|
|
{
|
|
{ "Circle1Arc", SLC_CASES().Circle1Arc, true, 1, 15, 1, 16 },
|
|
{ "Circle2Arcs", SLC_CASES().Circle2Arcs, true, 2, 16, 2, 17 },
|
|
{ "ArcsCoincident", SLC_CASES().ArcsCoincident, false, 2, 14, 3, 14 },
|
|
{ "ArcsCoincidentClosed", SLC_CASES().ArcsCoincidentClosed, true, 3, 14, 2, 14 },
|
|
{ "ArcsIndependent", SLC_CASES().ArcsIndependent, false, 3, 18, 4, 18 },
|
|
// SegAndArcCoincident will remove the segment after SetClosed(true) and SetClosed(false)
|
|
// disable test for now
|
|
//{ "SegAndArcCoincident", SLC_CASES().SegAndArcCoincident, false, 2, 92, 2, 91 },
|
|
{ "DuplicateArcs", SLC_CASES().DuplicateArcs, false, 4, 20, 5, 20 },
|
|
{ "ArcAndPoint", SLC_CASES().ArcAndPoint, false, 2, 10, 3, 10 },
|
|
{ "ArcsAndSegMixed", SLC_CASES().ArcsAndSegMixed, false, 4, 19, 5, 19 },
|
|
{ "OnePoint", SLC_CASES().OnePoint, false, 0, 1, 0, 1 }, // no shapes
|
|
{ "TwoPoints", SLC_CASES().TwoPoints, false, 1, 2, 2, 2 }, // there and back
|
|
{ "ThreePoints", SLC_CASES().ThreePoints, false, 2, 3, 3, 3 },
|
|
};
|
|
|
|
BOOST_AUTO_TEST_CASE( ToggleClosed )
|
|
{
|
|
for( const CLOSE_TOGGLE_SHAPE_CASE& c : close_toggle_shape_cases )
|
|
{
|
|
BOOST_TEST_CONTEXT( c.m_ctx_name )
|
|
{
|
|
SHAPE_LINE_CHAIN slc_case = c.m_chain; // make a copy to edit
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( slc_case ) );
|
|
BOOST_CHECK_EQUAL( slc_case.IsClosed(), c.m_closed );
|
|
BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
|
|
BOOST_CHECK_EQUAL( slc_case.PointCount(), c.m_point_count );
|
|
slc_case.SetClosed( !c.m_closed );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( slc_case ) );
|
|
BOOST_CHECK_EQUAL( slc_case.IsClosed(), !c.m_closed );
|
|
BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_expected_shape_count );
|
|
BOOST_CHECK_EQUAL( slc_case.PointCount(), c.m_expected_point_count );
|
|
slc_case.SetClosed( c.m_closed ); // toggle back to normal
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( slc_case ) );
|
|
BOOST_CHECK_EQUAL( slc_case.IsClosed(), c.m_closed );
|
|
BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
|
|
BOOST_CHECK_EQUAL( slc_case.PointCount(), c.m_point_count );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Test that duplicate point gets removed when we call simplify
|
|
BOOST_AUTO_TEST_CASE( SimplifyDuplicatePoint )
|
|
{
|
|
SHAPE_LINE_CHAIN chain;
|
|
|
|
chain.Append( { 100, 100 } );
|
|
chain.Append( { 100, 100 }, true ); //duplicate point to simplify
|
|
chain.Append( { 200, 100 } );
|
|
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 3 );
|
|
|
|
chain.Simplify();
|
|
|
|
BOOST_CHECK_EQUAL( chain.CPoints().size(), chain.CShapes().size() );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 2 ); // (-1) should have removed coincident points
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
}
|
|
|
|
|
|
// Test that duplicate point gets removed when we call simplify
|
|
BOOST_AUTO_TEST_CASE( SimplifyKeepEndPoint )
|
|
{
|
|
SHAPE_LINE_CHAIN chain;
|
|
|
|
chain.Append( { 114772424, 90949410 } );
|
|
chain.Append( { 114767360, 90947240 } );
|
|
chain.Append( { 114772429, 90947228 } );
|
|
chain.SetClosed( true );
|
|
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 3 );
|
|
|
|
chain.Simplify();
|
|
|
|
BOOST_CHECK_EQUAL( chain.CPoints().size(), chain.CShapes().size() );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 3 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
}
|
|
|
|
|
|
struct REMOVE_SHAPE_CASE
|
|
{
|
|
std::string m_ctx_name;
|
|
SHAPE_LINE_CHAIN m_chain;
|
|
int m_shape_count;
|
|
int m_arc_count;
|
|
int m_remove_index;
|
|
int m_expected_shape_count;
|
|
int m_expected_arc_count;
|
|
};
|
|
|
|
static const std::vector<REMOVE_SHAPE_CASE> remove_shape_cases =
|
|
{
|
|
{ "Circle1Arc - 1st arc - index on start", SLC_CASES().Circle1Arc, 1, 1, 0, 0, 0 },
|
|
{ "Circle1Arc - 1st arc - index on mid", SLC_CASES().Circle1Arc, 1, 1, 8, 0, 0 },
|
|
{ "Circle1Arc - 1st arc - index on end", SLC_CASES().Circle1Arc, 1, 1, 14, 0, 0 },
|
|
{ "Circle1Arc - 1st arc - index on -1", SLC_CASES().Circle1Arc, 1, 1, -1, 0, 0 },
|
|
{ "Circle1Arc - invalid index", SLC_CASES().Circle1Arc, 1, 1, 15, 1, 1 },
|
|
|
|
{ "Circle2Arcs - 1st arc - index on start", SLC_CASES().Circle2Arcs, 2, 2, 0, 2, 1 },
|
|
{ "Circle2Arcs - 1st arc - index on mid", SLC_CASES().Circle2Arcs, 2, 2, 3, 2, 1 },
|
|
{ "Circle2Arcs - 1st arc - index on end", SLC_CASES().Circle2Arcs, 2, 2, 7, 2, 1 },
|
|
{ "Circle2Arcs - 2nd arc - index on start", SLC_CASES().Circle2Arcs, 2, 2, 8, 2, 1 },
|
|
{ "Circle2Arcs - 2nd arc - index on mid", SLC_CASES().Circle2Arcs, 2, 2, 11, 2, 1 },
|
|
{ "Circle2Arcs - 2nd arc - index on end", SLC_CASES().Circle2Arcs, 2, 2, 15, 2, 1 },
|
|
{ "Circle2Arcs - 2nd arc - index on -1", SLC_CASES().Circle2Arcs, 2, 2, -1, 2, 1 },
|
|
{ "Circle2Arcs - invalid index", SLC_CASES().Circle2Arcs, 2, 2, 16, 2, 2 },
|
|
|
|
{ "ArcsCoinc. - 1st arc - idx on start", SLC_CASES().ArcsCoincident, 2, 2, 0, 1, 1 },
|
|
{ "ArcsCoinc. - 1st arc - idx on mid", SLC_CASES().ArcsCoincident, 2, 2, 3, 1, 1 },
|
|
{ "ArcsCoinc. - 1st arc - idx on end", SLC_CASES().ArcsCoincident, 2, 2, 7, 1, 1 },
|
|
{ "ArcsCoinc. - 2nd arc - idx on start", SLC_CASES().ArcsCoincident, 2, 2, 8, 1, 1 },
|
|
{ "ArcsCoinc. - 2nd arc - idx on mid", SLC_CASES().ArcsCoincident, 2, 2, 10, 1, 1 },
|
|
{ "ArcsCoinc. - 2nd arc - idx on end", SLC_CASES().ArcsCoincident, 2, 2, 13, 1, 1 },
|
|
{ "ArcsCoinc. - 2nd arc - idx on -1", SLC_CASES().ArcsCoincident, 2, 2, -1, 1, 1 },
|
|
{ "ArcsCoinc. - invalid idx", SLC_CASES().ArcsCoincident, 2, 2, 14, 2, 2 },
|
|
{ "ArcsCoinc. - 1st arc - idx on start", SLC_CASES().ArcsCoincident, 2, 2, 0, 1, 1 },
|
|
|
|
{ "A.Co.Closed - 1st arc - idx on start", SLC_CASES().ArcsCoincidentClosed, 3, 2, 1, 2, 1 },
|
|
{ "A.Co.Closed - 1st arc - idx on mid", SLC_CASES().ArcsCoincidentClosed, 3, 2, 3, 2, 1 },
|
|
{ "A.Co.Closed - 1st arc - idx on end", SLC_CASES().ArcsCoincidentClosed, 3, 2, 7, 2, 1 },
|
|
{ "A.Co.Closed - 2nd arc - idx on start", SLC_CASES().ArcsCoincidentClosed, 3, 2, 8, 2, 1 },
|
|
{ "A.Co.Closed - 2nd arc - idx on mid", SLC_CASES().ArcsCoincidentClosed, 3, 2, 10, 2, 1 },
|
|
{ "A.Co.Closed - 2nd arc - idx on end", SLC_CASES().ArcsCoincidentClosed, 3, 2, 13, 2, 1 },
|
|
{ "A.Co.Closed - 2nd arc - idx on -1", SLC_CASES().ArcsCoincidentClosed, 3, 2, -1, 2, 1 },
|
|
{ "A.Co.Closed - invalid idx", SLC_CASES().ArcsCoincidentClosed, 3, 2, 14, 3, 2 },
|
|
|
|
{ "ArcsIndep. - 1st arc - idx on start", SLC_CASES().ArcsIndependent, 3, 2, 0, 1, 1 },
|
|
{ "ArcsIndep. - 1st arc - idx on mid", SLC_CASES().ArcsIndependent, 3, 2, 3, 1, 1 },
|
|
{ "ArcsIndep. - 1st arc - idx on end", SLC_CASES().ArcsIndependent, 3, 2, 8, 1, 1 },
|
|
{ "ArcsIndep. - 2nd arc - idx on start", SLC_CASES().ArcsIndependent, 3, 2, 9, 1, 1 },
|
|
{ "ArcsIndep. - 2nd arc - idx on mid", SLC_CASES().ArcsIndependent, 3, 2, 12, 1, 1 },
|
|
{ "ArcsIndep. - 2nd arc - idx on end", SLC_CASES().ArcsIndependent, 3, 2, 17, 1, 1 },
|
|
{ "ArcsIndep. - 2nd arc - idx on -1", SLC_CASES().ArcsIndependent, 3, 2, -1, 1, 1 },
|
|
{ "ArcsIndep. - invalid idx", SLC_CASES().ArcsIndependent, 3, 2, 18, 3, 2 },
|
|
|
|
{ "Dup.Arcs - 1st arc - idx on start", SLC_CASES().DuplicateArcs, 4, 3, 0, 3, 2 },
|
|
{ "Dup.Arcs - 1st arc - idx on mid", SLC_CASES().DuplicateArcs, 4, 3, 3, 3, 2 },
|
|
{ "Dup.Arcs - 1st arc - idx on end", SLC_CASES().DuplicateArcs, 4, 3, 7, 3, 2 },
|
|
{ "Dup.Arcs - 2nd arc - idx on start", SLC_CASES().DuplicateArcs, 4, 3, 8, 3, 2 },
|
|
{ "Dup.Arcs - 2nd arc - idx on mid", SLC_CASES().DuplicateArcs, 4, 3, 10, 3, 2 },
|
|
{ "Dup.Arcs - 2nd arc - idx on end", SLC_CASES().DuplicateArcs, 4, 3, 13, 3, 2 },
|
|
{ "Dup.Arcs - 3rd arc - idx on start", SLC_CASES().DuplicateArcs, 4, 3, 14, 2, 2 },
|
|
{ "Dup.Arcs - 3rd arc - idx on mid", SLC_CASES().DuplicateArcs, 4, 3, 17, 2, 2 },
|
|
{ "Dup.Arcs - 3rd arc - idx on end", SLC_CASES().DuplicateArcs, 4, 3, 19, 2, 2 },
|
|
{ "Dup.Arcs - 3rd arc - idx on -1", SLC_CASES().DuplicateArcs, 4, 3, -1, 2, 2 },
|
|
{ "Dup.Arcs - invalid idx", SLC_CASES().DuplicateArcs, 4, 3, 20, 4, 3 },
|
|
|
|
{ "Arcs Mixed - 1st arc - idx on start", SLC_CASES().ArcsAndSegMixed, 4, 2, 0, 2, 1 },
|
|
{ "Arcs Mixed - 1st arc - idx on mid", SLC_CASES().ArcsAndSegMixed, 4, 2, 3, 2, 1 },
|
|
{ "Arcs Mixed - 1st arc - idx on end", SLC_CASES().ArcsAndSegMixed, 4, 2, 8, 2, 1 },
|
|
{ "Arcs Mixed - Straight segment", SLC_CASES().ArcsAndSegMixed, 4, 2, 9, 3, 2 },
|
|
{ "Arcs Mixed - 2nd arc - idx on start", SLC_CASES().ArcsAndSegMixed, 4, 2, 10, 2, 1 },
|
|
{ "Arcs Mixed - 2nd arc - idx on mid", SLC_CASES().ArcsAndSegMixed, 4, 2, 14, 2, 1 },
|
|
{ "Arcs Mixed - 2nd arc - idx on end", SLC_CASES().ArcsAndSegMixed, 4, 2, 18, 2, 1 },
|
|
{ "Arcs Mixed - 2nd arc - idx on -1", SLC_CASES().ArcsAndSegMixed, 4, 2, -1, 2, 1 },
|
|
{ "Arcs Mixed - invalid idx", SLC_CASES().ArcsAndSegMixed, 4, 2, 19, 4, 2 }
|
|
};
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE( RemoveShape )
|
|
{
|
|
for( const REMOVE_SHAPE_CASE& c : remove_shape_cases )
|
|
{
|
|
BOOST_TEST_CONTEXT( c.m_ctx_name )
|
|
{
|
|
SHAPE_LINE_CHAIN slc_case = c.m_chain; // make a copy to edit
|
|
BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
|
|
BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_arc_count );
|
|
BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
|
|
slc_case.RemoveShape( c.m_remove_index );
|
|
BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_expected_shape_count );
|
|
BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_expected_arc_count );
|
|
BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE( RemoveShapeAfterSimplify )
|
|
{
|
|
for( const REMOVE_SHAPE_CASE& c : remove_shape_cases )
|
|
{
|
|
BOOST_TEST_CONTEXT( c.m_ctx_name )
|
|
{
|
|
SHAPE_LINE_CHAIN slc_case = c.m_chain; // make a copy to edit
|
|
BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
|
|
BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
|
|
BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_arc_count );
|
|
slc_case.Simplify();
|
|
BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
|
|
BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_shape_count );
|
|
BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_arc_count );
|
|
slc_case.RemoveShape( c.m_remove_index );
|
|
BOOST_CHECK_EQUAL( GEOM_TEST::IsOutlineValid( slc_case ), true );
|
|
BOOST_CHECK_EQUAL( slc_case.ShapeCount(), c.m_expected_shape_count );
|
|
BOOST_CHECK_EQUAL( slc_case.ArcCount(), c.m_expected_arc_count );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE( ShapeCount )
|
|
{
|
|
BOOST_CHECK_EQUAL( Circle1Arc.ShapeCount(), 1 );
|
|
BOOST_CHECK_EQUAL( Circle2Arcs.ShapeCount(), 2 );
|
|
BOOST_CHECK_EQUAL( ArcsCoincident.ShapeCount(), 2 );
|
|
BOOST_CHECK_EQUAL( ArcsCoincidentClosed.ShapeCount(), 3 );
|
|
BOOST_CHECK_EQUAL( DuplicateArcs.ShapeCount(), 4 );
|
|
BOOST_CHECK_EQUAL( ArcAndPoint.ShapeCount(), 2 );
|
|
BOOST_CHECK_EQUAL( ArcsAndSegMixed.ShapeCount(), 4 );
|
|
BOOST_CHECK_EQUAL( SegAndArcCoincident.ShapeCount(), 2 );
|
|
BOOST_CHECK_EQUAL( EmptyChain.ShapeCount(), 0 );
|
|
BOOST_CHECK_EQUAL( OnePoint.ShapeCount(), 0 );
|
|
BOOST_CHECK_EQUAL( TwoPoints.ShapeCount(), 1 );
|
|
BOOST_CHECK_EQUAL( ThreePoints.ShapeCount(), 2 );
|
|
}
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE( NextShape )
|
|
{
|
|
BOOST_CHECK_EQUAL( Circle1Arc.NextShape( 0 ), -1 ); //only one arc
|
|
|
|
BOOST_CHECK_EQUAL( Circle2Arcs.NextShape( 0 ), 8 ); // next shape "Arc0b"
|
|
BOOST_CHECK_EQUAL( Circle2Arcs.NextShape( 8 ), -1 ); //no more shapes (last point joins with first, part of arc)
|
|
|
|
BOOST_CHECK_EQUAL( ArcsCoincident.NextShape( 0 ), 8 ); // next shape "Arc1"
|
|
BOOST_CHECK_EQUAL( ArcsCoincident.NextShape( 8 ), -1 ); //no more shapes
|
|
|
|
BOOST_CHECK_EQUAL( ArcsCoincidentClosed.NextShape( 0 ), 8 ); // next shape "Arc1"
|
|
BOOST_CHECK_EQUAL( ArcsCoincidentClosed.NextShape( 8 ), 13 ); //next shape is hidden segment joining last/first
|
|
BOOST_CHECK_EQUAL( ArcsCoincidentClosed.NextShape( 13 ), -1 ); //no more shapes
|
|
|
|
BOOST_CHECK_EQUAL( ArcsIndependent.NextShape( 0 ), 8 ); // next shape straight seg
|
|
BOOST_CHECK_EQUAL( ArcsIndependent.NextShape( 8 ), 9 ); //next shape second arc
|
|
BOOST_CHECK_EQUAL( ArcsIndependent.NextShape( 9 ), -1 ); //no more shapes
|
|
|
|
BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 0 ), 8 ); // next shape "Arc1"
|
|
BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 8 ), 13 ); // next shape hidden segment joining the 2 duplicate arcs
|
|
BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 13 ), 14 ); // next shape "Arc1" (duplicate)
|
|
BOOST_CHECK_EQUAL( DuplicateArcs.NextShape( 14 ), -1 ); //no more shapes
|
|
|
|
BOOST_CHECK_EQUAL( ArcAndPoint.NextShape( 0 ), 8 ); // next shape straight segment (end of arc->point)
|
|
BOOST_CHECK_EQUAL( ArcAndPoint.NextShape( 8 ), -1 ); //no more shapes
|
|
|
|
BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 0 ), 8 ); // next shape straight segment (end of arc->point)
|
|
BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 8 ), 9 ); // next shape straight segment (point->begining of arc)
|
|
BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 9 ), 10 ); //next shape second arc
|
|
BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 10 ), -1 ); //no more shapes
|
|
BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( 20 ), -1 ); //invalid indices should still work
|
|
BOOST_CHECK_EQUAL( ArcsAndSegMixed.NextShape( -50 ), -1 ); //invalid indices should still work
|
|
|
|
BOOST_CHECK_EQUAL( SegAndArcCoincident.NextShape( 0 ), 1 ); // next shape Arc3
|
|
BOOST_CHECK_EQUAL( SegAndArcCoincident.NextShape( 1 ), -1 ); //no more shapes
|
|
|
|
BOOST_CHECK_EQUAL( EmptyChain.NextShape( 0 ), -1 );
|
|
BOOST_CHECK_EQUAL( EmptyChain.NextShape( 1 ), -1 ); //invalid indices should still work
|
|
BOOST_CHECK_EQUAL( EmptyChain.NextShape( 2 ), -1 ); //invalid indices should still work
|
|
BOOST_CHECK_EQUAL( EmptyChain.NextShape( -2 ), -1 ); //invalid indices should still work
|
|
|
|
BOOST_CHECK_EQUAL( OnePoint.NextShape( 0 ), -1 );
|
|
BOOST_CHECK_EQUAL( OnePoint.NextShape( -1 ), -1 );
|
|
BOOST_CHECK_EQUAL( OnePoint.NextShape( 1 ), -1 ); //invalid indices should still work
|
|
BOOST_CHECK_EQUAL( OnePoint.NextShape( 2 ), -1 ); //invalid indices should still work
|
|
BOOST_CHECK_EQUAL( OnePoint.NextShape( -2 ), -1 ); //invalid indices should still work
|
|
|
|
BOOST_CHECK_EQUAL( TwoPoints.NextShape( 0 ), -1 );
|
|
BOOST_CHECK_EQUAL( TwoPoints.NextShape( 1 ), -1 );
|
|
BOOST_CHECK_EQUAL( TwoPoints.NextShape( -1 ), -1 );
|
|
|
|
BOOST_CHECK_EQUAL( ThreePoints.NextShape( 0 ), 1 );
|
|
BOOST_CHECK_EQUAL( ThreePoints.NextShape( 1 ), -1 );
|
|
BOOST_CHECK_EQUAL( ThreePoints.NextShape( 2 ), -1 );
|
|
BOOST_CHECK_EQUAL( ThreePoints.NextShape( -1 ), -1 );
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE( AppendArc )
|
|
{
|
|
BOOST_TEST_CONTEXT( "Case 1: Arc mid point nearly collinear" )
|
|
{
|
|
SHAPE_ARC arc( VECTOR2I( 100000, 0 ), VECTOR2I( 0, 2499 ), VECTOR2I( -100000, 0 ), 0 );
|
|
SHAPE_LINE_CHAIN chain;
|
|
chain.Append( arc, 5000 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
|
|
BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 100000, 0 ) ); //arc start
|
|
BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( -100000, 0 ) ); //arc end
|
|
BOOST_CHECK_EQUAL( chain.GetPoint( -1 ), VECTOR2I( -100000, 0 ) ); //arc end
|
|
}
|
|
|
|
BOOST_TEST_CONTEXT( "Case 2: Arc = Large Circle" )
|
|
{
|
|
SHAPE_ARC arc( VECTOR2I( 100000, 0 ), VECTOR2I( 0, 0 ), VECTOR2I( 100000, 0 ), 0 );
|
|
SHAPE_LINE_CHAIN chain;
|
|
chain.Append( arc, 5000 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
BOOST_CHECK_EQUAL( chain.ArcCount(), 1 );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 10 );
|
|
BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 100000, 0 ) ); //arc start
|
|
BOOST_CHECK_EQUAL( chain.GetPoint( 9 ), VECTOR2I( 100000, 0 ) ); //arc end
|
|
BOOST_CHECK_EQUAL( chain.GetPoint( -1 ), VECTOR2I( 100000, 0 ) ); //arc end
|
|
}
|
|
|
|
BOOST_TEST_CONTEXT( "Case 3: Arc = Small Circle (approximate to point)" )
|
|
{
|
|
SHAPE_ARC arc( VECTOR2I( 2499, 0 ), VECTOR2I( 0, 0 ), VECTOR2I( 2499, 0 ), 0 );
|
|
SHAPE_LINE_CHAIN chain;
|
|
chain.Append( arc, 5000 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 1 );
|
|
BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 2499, 0 ) ); //arc start
|
|
}
|
|
|
|
BOOST_TEST_CONTEXT( "Case 3: Small Arc (approximate to segment)" )
|
|
{
|
|
SHAPE_ARC arc( VECTOR2I( 1767, 0 ), VECTOR2I( 2499, 2499 ), VECTOR2I( 0, 1767 ), 0 );
|
|
SHAPE_LINE_CHAIN chain;
|
|
chain.Append( arc, 5000 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
|
|
BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 1767, 0 ) ); //arc start
|
|
BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( 0, 1767 ) ); //arc end
|
|
}
|
|
|
|
BOOST_TEST_CONTEXT( "Case 4: Arc = null arc (all points coincident)" )
|
|
{
|
|
SHAPE_ARC arc( VECTOR2I( 2499, 0 ), VECTOR2I( 2499, 0 ), VECTOR2I( 2499, 0 ), 0 );
|
|
SHAPE_LINE_CHAIN chain;
|
|
chain.Append( arc, 5000 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 1 );
|
|
BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 2499, 0 ) ); //arc start
|
|
}
|
|
|
|
BOOST_TEST_CONTEXT( "Case 5: Arc = infinite radius (all points very close)" )
|
|
{
|
|
SHAPE_ARC arc( VECTOR2I( 2499, 0 ), VECTOR2I( 2500, 0 ), VECTOR2I( 2501, 0 ), 0 );
|
|
SHAPE_LINE_CHAIN chain;
|
|
chain.Append( arc, 5000 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
|
|
BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( 2499, 0 ) ); //arc start
|
|
BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( 2501, 0 ) ); //arc end
|
|
}
|
|
|
|
BOOST_TEST_CONTEXT( "Case 6: Arc = large radius (all points very close)" )
|
|
{
|
|
SHAPE_ARC arc( VECTOR2I( -100000, 0 ), VECTOR2I( 0, 1 ), VECTOR2I( 100000, 0 ), 0 );
|
|
SHAPE_LINE_CHAIN chain;
|
|
chain.Append( arc, 5000 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
BOOST_CHECK_EQUAL( chain.ArcCount(), 0 );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
|
|
BOOST_CHECK_EQUAL( chain.GetPoint( 0 ), VECTOR2I( -100000, 0 ) ); //arc start
|
|
BOOST_CHECK_EQUAL( chain.GetPoint( 1 ), VECTOR2I( 100000, 0 ) ); //arc end
|
|
}
|
|
}
|
|
|
|
|
|
// Test special case where the last arc in the chain has a shared point with the first arc
|
|
BOOST_AUTO_TEST_CASE( ArcWrappingToStartSharedPoints )
|
|
{
|
|
// represent a circle with two semicircular arcs
|
|
SHAPE_ARC arc1( VECTOR2I( 100000, 0 ), VECTOR2I( 0, 100000 ), VECTOR2I( -100000, 0 ), 0 );
|
|
SHAPE_ARC arc2( VECTOR2I( -100000, 0 ), VECTOR2I( 0, -100000 ), VECTOR2I( 100000, 0 ), 0 );
|
|
|
|
// Start a chain with the two arcs
|
|
SHAPE_LINE_CHAIN chain;
|
|
chain.Append( arc1 );
|
|
chain.Append( arc2 );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 13 );
|
|
//BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
|
|
// OPEN CHAIN
|
|
// Start of the chain is not yet a shared point, so can't be an arc end either
|
|
BOOST_CHECK_EQUAL( chain.IsSharedPt( 0 ), false );
|
|
BOOST_CHECK_EQUAL( chain.IsArcEnd( 0 ), false );
|
|
BOOST_CHECK_EQUAL( chain.IsArcStart( 0 ), true );
|
|
|
|
// Index 6 is the shared point between the two arcs in the middle of the chain
|
|
BOOST_CHECK_EQUAL( chain.IsSharedPt( 6 ), true );
|
|
BOOST_CHECK_EQUAL( chain.IsArcEnd( 6 ), true );
|
|
BOOST_CHECK_EQUAL( chain.IsArcStart( 6 ), true );
|
|
|
|
// End index is not yet a shared point
|
|
int endIndex = chain.PointCount() - 1;
|
|
BOOST_CHECK_EQUAL( chain.IsSharedPt( endIndex ), false );
|
|
BOOST_CHECK_EQUAL( chain.IsArcEnd( endIndex ), true );
|
|
BOOST_CHECK_EQUAL( chain.IsArcStart( endIndex ), false );
|
|
|
|
for( int i = 0; i < chain.PointCount(); i++ )
|
|
{
|
|
BOOST_CHECK_EQUAL( chain.IsPtOnArc( i ), true ); // all points in the chain are arcs
|
|
}
|
|
|
|
// CLOSED CHAIN
|
|
chain.SetClosed( true );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 12 ); // (-1) should have removed coincident points
|
|
//BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
|
|
// Start of the chain should be a shared point now, so can't be an arc end either
|
|
BOOST_CHECK_EQUAL( chain.IsSharedPt( 0 ), true );
|
|
BOOST_CHECK_EQUAL( chain.IsArcEnd( 0 ), true );
|
|
BOOST_CHECK_EQUAL( chain.IsArcStart( 0 ), true );
|
|
|
|
// Index 6 is the shared point between the two arcs in the middle of the chain
|
|
BOOST_CHECK_EQUAL( chain.IsSharedPt( 6 ), true );
|
|
BOOST_CHECK_EQUAL( chain.IsArcEnd( 6 ), true );
|
|
BOOST_CHECK_EQUAL( chain.IsArcStart( 6 ), true );
|
|
|
|
// End index is in the middle of an arc, so not an end point or shared point
|
|
endIndex = chain.PointCount() - 1;
|
|
BOOST_CHECK_EQUAL( chain.IsSharedPt( endIndex ), false );
|
|
BOOST_CHECK_EQUAL( chain.IsArcEnd( endIndex ), false );
|
|
BOOST_CHECK_EQUAL( chain.IsArcStart( endIndex ), false );
|
|
}
|
|
|
|
// Test SHAPE_LINE_CHAIN::Split()
|
|
BOOST_AUTO_TEST_CASE( Split )
|
|
{
|
|
SEG seg1( VECTOR2I( 0, 100000 ), VECTOR2I( 50000, 0 ) );
|
|
SEG seg2( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
|
|
SHAPE_ARC arc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
|
|
|
|
// Start a chain with 2 points (seg1)
|
|
SHAPE_LINE_CHAIN chain( { seg1.A, seg1.B } );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
|
|
// Add first arc
|
|
chain.Append( arc );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 9 );
|
|
// Add two points (seg2)
|
|
chain.Append( seg2.A );
|
|
chain.Append( seg2.B );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 11 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
|
|
BOOST_TEST_CONTEXT( "Case 1: Point not in the chain" )
|
|
{
|
|
SHAPE_LINE_CHAIN chainCopy = chain;
|
|
BOOST_CHECK_EQUAL( chainCopy.Split( VECTOR2I( 400000, 0 ) ), -1 );
|
|
BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() );
|
|
BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
|
|
}
|
|
|
|
BOOST_TEST_CONTEXT( "Case 2: Point close to start of a segment" )
|
|
{
|
|
SHAPE_LINE_CHAIN chainCopy = chain;
|
|
VECTOR2I splitPoint = seg1.A + VECTOR2I( 5, -10 );
|
|
BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 1 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chainCopy ) );
|
|
BOOST_CHECK_EQUAL( chainCopy.GetPoint( 1 ), splitPoint );
|
|
BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() + 1 ); // new point added
|
|
BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
|
|
}
|
|
|
|
BOOST_TEST_CONTEXT( "Case 3: Point exactly on the segment" )
|
|
{
|
|
SHAPE_LINE_CHAIN chainCopy = chain;
|
|
VECTOR2I splitPoint = seg1.B;
|
|
BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 1 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chainCopy ) );
|
|
BOOST_CHECK_EQUAL( chainCopy.GetPoint( 1 ), splitPoint );
|
|
BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() );
|
|
BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
|
|
}
|
|
|
|
BOOST_TEST_CONTEXT( "Case 4: Point at start of arc" )
|
|
{
|
|
SHAPE_LINE_CHAIN chainCopy = chain;
|
|
VECTOR2I splitPoint = arc.GetP0();
|
|
BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 2 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chainCopy ) );
|
|
BOOST_CHECK_EQUAL( chainCopy.GetPoint( 2 ), splitPoint );
|
|
BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() );
|
|
BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() );
|
|
}
|
|
|
|
BOOST_TEST_CONTEXT( "Case 5: Point close to start of arc" )
|
|
{
|
|
SHAPE_LINE_CHAIN chainCopy = chain;
|
|
VECTOR2I splitPoint = arc.GetP0() + VECTOR2I( -10, 130 );
|
|
BOOST_CHECK_EQUAL( chainCopy.Split( splitPoint ), 3 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chainCopy ) );
|
|
BOOST_CHECK_EQUAL( chainCopy.GetPoint( 3 ), splitPoint );
|
|
BOOST_CHECK_EQUAL( chainCopy.IsSharedPt( 3 ), true ); // must be a shared point
|
|
BOOST_CHECK_EQUAL( chainCopy.PointCount(), chain.PointCount() + 1 ); // new point added
|
|
BOOST_CHECK_EQUAL( chainCopy.ArcCount(), chain.ArcCount() + 1 ); // new arc should have been created
|
|
}
|
|
}
|
|
|
|
|
|
// Test SHAPE_LINE_CHAIN::Slice()
|
|
BOOST_AUTO_TEST_CASE( Slice )
|
|
{
|
|
SEG targetSegment( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
|
|
SHAPE_ARC firstArc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
|
|
SHAPE_ARC secondArc( VECTOR2I( -200000, -200000 ), VECTOR2I( -300000, -100000 ), -ANGLE_180 );
|
|
int tol = SHAPE_ARC::DefaultAccuracyForPCB(); // Tolerance for arc collisions
|
|
|
|
// Start a chain with 3 points
|
|
SHAPE_LINE_CHAIN chain( { VECTOR2I( 0, 0 ), VECTOR2I( 0, 100000 ), VECTOR2I( 100000, 0 ) } );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 3 );
|
|
// Add first arc
|
|
chain.Append( firstArc );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 10 );
|
|
// Add two points (target segment)
|
|
chain.Append( targetSegment.A );
|
|
chain.Append( targetSegment.B );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 12 );
|
|
// Add a second arc
|
|
chain.Append( secondArc );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 20 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
|
|
//////////////////////////////////////////////////////////
|
|
/// CASE 1: Start at arc endpoint, finish middle of arc /
|
|
//////////////////////////////////////////////////////////
|
|
BOOST_TEST_CONTEXT( "Case 1: Start at arc endpoint, finish middle of arc" )
|
|
{
|
|
SHAPE_LINE_CHAIN sliceResult = chain.Slice( 9, 18 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
|
|
SHAPE_ARC expectedSliceArc0;
|
|
expectedSliceArc0.ConstructFromStartEndCenter( secondArc.GetP0(), chain.GetPoint( 18 ),
|
|
secondArc.GetCenter(),
|
|
secondArc.IsClockwise() );
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.Arc( 0 ).GetP0(), expectedSliceArc0.GetP0() ); // equal arc start points
|
|
BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetArcMid(), tol ) );
|
|
BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetP1(), tol ) );
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.PointCount(), 10 );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), firstArc.GetP1() ); // equal to arc end
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 1 ), targetSegment.A );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 2 ), targetSegment.B );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 3 ), expectedSliceArc0.GetP0() ); // equal to arc start
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 3 ), true );
|
|
|
|
for( int i = 4; i <= 8; i++ )
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
|
|
|
|
for( int i = 3; i <= 7; i++ )
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 9 ), true );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 9 ), expectedSliceArc0.GetP1() ); // equal to arc end
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
/// CASE 2: Start at middle of an arc, finish at arc startpoint /
|
|
//////////////////////////////////////////////////////////////////
|
|
BOOST_TEST_CONTEXT( "Case 2: Start at middle of an arc, finish at arc startpoint" )
|
|
{
|
|
SHAPE_LINE_CHAIN sliceResult = chain.Slice( 5, 12 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
|
|
SHAPE_ARC expectedSliceArc0;
|
|
expectedSliceArc0.ConstructFromStartEndCenter( chain.GetPoint( 5 ), firstArc.GetP1(),
|
|
firstArc.GetCenter(),
|
|
firstArc.IsClockwise() );
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.Arc( 0 ).GetP1(),
|
|
expectedSliceArc0.GetP1() ); // equal arc end points
|
|
BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetArcMid(), tol ) );
|
|
BOOST_CHECK( sliceResult.Arc( 0 ).Collide( expectedSliceArc0.GetP0(), tol ) );
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.PointCount(), 8 );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ),
|
|
expectedSliceArc0.GetP0() ); // equal to arc start
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
|
|
|
|
for( int i = 1; i <= 4; i++ )
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
|
|
|
|
for( int i = 0; i <= 3; i++ )
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 4 ), true );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 4 ),
|
|
expectedSliceArc0.GetP1() ); // equal to arc end
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 5 ), targetSegment.A );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), targetSegment.B );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 7 ), secondArc.GetP0() );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
/// CASE 3: Full arc, nothing else /
|
|
//////////////////////////////////////////////////////////////////
|
|
BOOST_TEST_CONTEXT( "Case 3: Full arc, nothing else" )
|
|
{
|
|
SHAPE_LINE_CHAIN sliceResult = chain.Slice( 3, 9 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
|
|
SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
|
|
|
|
// Equal arc to original inserted arc
|
|
BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
|
|
BOOST_CHECK_EQUAL( firstArc.GetArcMid(), sliceArc0.GetArcMid() );
|
|
BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.PointCount(), 7 );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), sliceArc0.GetP0() ); // equal to arc start
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
|
|
|
|
for( int i = 1; i <= 6; i++ )
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
|
|
|
|
for( int i = 0; i <= 5; i++ )
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 6 ), true );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), sliceArc0.GetP1() ); // equal to arc end
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
/// CASE 4: Full arc, and straight segments to next arc start /
|
|
//////////////////////////////////////////////////////////////////
|
|
BOOST_TEST_CONTEXT( "Case 4: Full arc, and straight segments to next arc start" )
|
|
{
|
|
SHAPE_LINE_CHAIN sliceResult = chain.Slice( 3, 12 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.ArcCount(), 1 );
|
|
SHAPE_ARC sliceArc0 = sliceResult.Arc( 0 );
|
|
|
|
// Equal arc to original inserted arc
|
|
BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
|
|
BOOST_CHECK_EQUAL( firstArc.GetArcMid(), sliceArc0.GetArcMid() );
|
|
BOOST_CHECK_EQUAL( firstArc.GetP1(), sliceArc0.GetP1() );
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.PointCount(), 10 );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), sliceArc0.GetP0() ); // equal to arc start
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcStart( 0 ), true );
|
|
|
|
for( int i = 1; i <= 6; i++ )
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcStart( i ), false );
|
|
|
|
for( int i = 0; i <= 5; i++ )
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( i ), false );
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.IsArcEnd( 6 ), true );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 6 ), sliceArc0.GetP1() ); // equal to arc end
|
|
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 7 ), targetSegment.A );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 8 ), targetSegment.B );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 9 ), secondArc.GetP0() );
|
|
}
|
|
|
|
BOOST_TEST_CONTEXT( "Case 5: Chain ends in arc and point" )
|
|
{
|
|
SHAPE_LINE_CHAIN chainCopy = chain;
|
|
chainCopy.Append( VECTOR2I( 400000, 400000 ) );
|
|
|
|
SHAPE_LINE_CHAIN sliceResult = chainCopy.Slice( 11, -1 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( sliceResult ) );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( -1 ), VECTOR2I( 400000, 400000 ) );
|
|
}
|
|
|
|
BOOST_TEST_CONTEXT( "Case 6: Start to end, chain with one point" )
|
|
{
|
|
SHAPE_LINE_CHAIN chainCopy = SLC_CASES().OnePoint;
|
|
|
|
SHAPE_LINE_CHAIN sliceResult = chainCopy.Slice( 0, -1 );
|
|
BOOST_CHECK_EQUAL( sliceResult.PointCount(), 1 );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), VECTOR2I( 233450000, 228360000 ) );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( -1 ), VECTOR2I( 233450000, 228360000 ) ); // Same as index 0
|
|
}
|
|
|
|
BOOST_TEST_CONTEXT( "Case 7: Start to end, chain with two points" )
|
|
{
|
|
SHAPE_LINE_CHAIN chainCopy = SLC_CASES().TwoPoints;
|
|
|
|
SHAPE_LINE_CHAIN sliceResult = chainCopy.Slice( 0, -1 );
|
|
BOOST_CHECK_EQUAL( sliceResult.PointCount(), 2 );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 0 ), VECTOR2I( 233450000, 228360000 ) );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( 1 ), VECTOR2I( 263450000, 258360000 ) );
|
|
BOOST_CHECK_EQUAL( sliceResult.GetPoint( -1 ), VECTOR2I( 263450000, 258360000 ) ); // Same as index 1
|
|
}
|
|
}
|
|
|
|
|
|
// Test SHAPE_LINE_CHAIN::NearestPoint( VECTOR2I )
|
|
BOOST_AUTO_TEST_CASE( NearestPointPt )
|
|
{
|
|
SEG seg1( VECTOR2I( 0, 100000 ), VECTOR2I( 50000, 0 ) );
|
|
SEG seg2( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ) );
|
|
SHAPE_ARC arc( VECTOR2I( 200000, 0 ), VECTOR2I( 300000, 0 ), ANGLE_180 );
|
|
|
|
// Start a chain with 2 points (seg1)
|
|
SHAPE_LINE_CHAIN chain( { seg1.A, seg1.B } );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 2 );
|
|
// Add first arc
|
|
chain.Append( arc );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 9 );
|
|
// Add two points (seg2)
|
|
chain.Append( seg2.A );
|
|
chain.Append( seg2.B );
|
|
BOOST_CHECK_EQUAL( chain.PointCount(), 11 );
|
|
BOOST_CHECK( GEOM_TEST::IsOutlineValid( chain ) );
|
|
|
|
VECTOR2I ptOnArcCloseToStart( 297553, 31697 ); //should be index 3 in chain
|
|
VECTOR2I ptOnArcCloseToEnd( 139709, 82983 ); //should be index 6 in chain
|
|
|
|
BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToStart, true ), ptOnArcCloseToStart );
|
|
BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToStart, false ), arc.GetP0() );
|
|
|
|
BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToEnd, true ), ptOnArcCloseToEnd );
|
|
BOOST_CHECK_EQUAL( chain.NearestPoint( ptOnArcCloseToEnd, false ), arc.GetP1() );
|
|
}
|
|
|
|
|
|
// Test SHAPE_LINE_CHAIN::Replace( SHAPE_LINE_CHAIN )
|
|
BOOST_AUTO_TEST_CASE( ReplaceChain )
|
|
{
|
|
BOOST_TEST_INFO( "8949 crash" );
|
|
|
|
std::vector<VECTOR2I> linePts = {
|
|
{ 206000000, 140110000 }, { 192325020, 140110000 }, { 192325020, 113348216 },
|
|
{ 192251784, 113274980 }, { 175548216, 113274980 }, { 175474980, 113348216 },
|
|
{ 175474980, 136694980 }, { 160774511, 121994511 }, { 160774511, 121693501 },
|
|
{ 160086499, 121005489 }, { 159785489, 121005489 }, { 159594511, 120814511 },
|
|
{ 160086499, 120814511 }, { 160774511, 120126499 }, { 160774511, 119153501 },
|
|
{ 160086499, 118465489 }, { 159113501, 118465489 }, { 158425489, 119153501 },
|
|
{ 158425489, 119645489 }, { 157325020, 118545020 }, { 157325020, 101925020 },
|
|
{ 208674980, 101925020 }, { 208674980, 145474980 }, { 192325020, 145474980 },
|
|
{ 192325020, 140110000 }
|
|
};
|
|
|
|
SHAPE_LINE_CHAIN baseChain( linePts, false );
|
|
baseChain.SetWidth( 250000 );
|
|
BOOST_CHECK_EQUAL( baseChain.PointCount(), linePts.size() );
|
|
|
|
SHAPE_LINE_CHAIN replaceChain( { VECTOR2I( 192325020, 140110000 ) }, false );
|
|
BOOST_CHECK_EQUAL( replaceChain.PointCount(), 1 );
|
|
|
|
baseChain.Replace( 1, 23, replaceChain );
|
|
|
|
BOOST_CHECK_EQUAL( baseChain.PointCount(), linePts.size() - ( 23 - 1 ) );
|
|
|
|
// Replacing the last point in a chain is special-cased
|
|
baseChain.Replace( baseChain.PointCount() - 1, baseChain.PointCount() - 1, VECTOR2I( -1, -1 ) );
|
|
|
|
BOOST_CHECK_EQUAL( baseChain.CLastPoint(), VECTOR2I( -1, -1 ) );
|
|
}
|
|
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|