KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_issue25110_bezier_line_style.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <cmath>
21#include <numeric>
22#include <vector>
23
25
26#include <base_units.h>
28#include <pcb_painter.h>
29#include <pcb_shape.h>
30#include <stroke_params.h>
31
32
33BOOST_AUTO_TEST_SUITE( Issue25110 )
34
35
36// A dash that spans a vertex of the flattened curve arrives as several touching pieces, so
37// glue the pieces back together before measuring anything.
39{
40 std::vector<double> drawn; // length of each dash actually drawn
41 std::vector<double> gaps; // distance from the end of one dash to the start of the next
42};
43
44
45static DASH_RUNS collectRuns( const SHAPE* aShape, LINE_STYLE aStyle, int aWidth,
46 const KIGFX::RENDER_SETTINGS* aSettings )
47{
48 std::vector<SEG> pieces;
49
50 STROKE_PARAMS::Stroke( aShape, aStyle, aWidth, aSettings,
51 [&pieces]( const VECTOR2I& a, const VECTOR2I& b )
52 {
53 pieces.emplace_back( a, b );
54 } );
55
56 DASH_RUNS runs;
57
58 for( size_t ii = 0; ii < pieces.size(); )
59 {
60 double length = VECTOR2D( pieces[ii].B - pieces[ii].A ).EuclideanNorm();
61 VECTOR2I end = pieces[ii].B;
62 size_t jj = ii + 1;
63
64 while( jj < pieces.size() && pieces[jj].A == end )
65 {
66 length += VECTOR2D( pieces[jj].B - pieces[jj].A ).EuclideanNorm();
67 end = pieces[jj].B;
68 jj++;
69 }
70
71 runs.drawn.push_back( length );
72
73 if( jj < pieces.size() )
74 runs.gaps.push_back( VECTOR2D( pieces[jj].A - end ).EuclideanNorm() );
75
76 ii = jj;
77 }
78
79 return runs;
80}
81
82
84{
85 PCB_SHAPE shape( nullptr, SHAPE_T::BEZIER );
86
87 shape.SetStart( { 0, 0 } );
88 shape.SetBezierC1( { pcbIUScale.mmToIU( 5 ), pcbIUScale.mmToIU( -8 ) } );
89 shape.SetBezierC2( { pcbIUScale.mmToIU( 15 ), pcbIUScale.mmToIU( 8 ) } );
90 shape.SetEnd( { pcbIUScale.mmToIU( 20 ), 0 } );
92
93 return SHAPE_LINE_CHAIN( shape.GetBezierPoints() );
94}
95
96
97// A Bezier is flattened into segments far shorter than one dash, so stroking them one at a
98// time drew each of them in full and the curve came out solid.
99BOOST_AUTO_TEST_CASE( BezierDashedLineHasGaps )
100{
102
103 const int width = pcbIUScale.mmToIU( 0.1 );
105
106 double curveLength = 0.0;
107
108 for( int ii = 0; ii < chain.SegmentCount(); ++ii )
109 curveLength += VECTOR2D( chain.CSegment( ii ).B - chain.CSegment( ii ).A ).EuclideanNorm();
110
111 const double dashLength = settings.GetDashLength( width );
112 const double gapLength = settings.GetGapLength( width );
113
114 DASH_RUNS runs = collectRuns( &chain, LINE_STYLE::DASH, width, &settings );
115
116 BOOST_REQUIRE_MESSAGE( runs.drawn.size() > 5,
117 "expected the curve to be broken into dashes, got " << runs.drawn.size() << " run(s)" );
118
119 double drawn = std::accumulate( runs.drawn.begin(), runs.drawn.end(), 0.0 );
120 double expected = curveLength * dashLength / ( dashLength + gapLength );
121
122 BOOST_CHECK_MESSAGE( std::abs( drawn - expected ) < 0.02 * curveLength,
123 "dashes should cover " << expected << " IU of the " << curveLength << " IU curve, they cover "
124 << drawn );
125}
126
127
128// Restarting the pattern on every flattened segment put a dot on every vertex, so the dots
129// followed the tessellation instead of being evenly spaced.
130BOOST_AUTO_TEST_CASE( BezierDottedLineIsEvenlySpaced )
131{
133
134 const int width = pcbIUScale.mmToIU( 0.1 );
136
137 const double gapLength = settings.GetGapLength( width );
138
139 DASH_RUNS runs = collectRuns( &chain, LINE_STYLE::DOT, width, &settings );
140
141 BOOST_REQUIRE_MESSAGE( runs.gaps.size() > 5, "expected a row of dots, got " << runs.drawn.size() << " run(s)" );
142
143 for( size_t ii = 0; ii < runs.gaps.size(); ++ii )
144 {
145 BOOST_CHECK_MESSAGE( std::abs( runs.gaps[ii] - gapLength ) < 0.03 * gapLength,
146 "dot " << ii << " sits " << runs.gaps[ii] << " IU from the previous one, expected "
147 << gapLength );
148 }
149}
150
151
constexpr int ARC_HIGH_DEF
Definition base_units.h:137
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
void RebuildBezierToSegmentsPointsList(int aMaxError)
Rebuild the m_bezierPoints vertex list that approximate the Bezier curve by a list of segments.
const std::vector< VECTOR2I > & GetBezierPoints() const
Definition eda_shape.h:491
PCB specific render settings.
Definition pcb_painter.h:84
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
double GetGapLength(int aLineWidth) const
double GetDashLength(int aLineWidth) const
void SetBezierC1(const VECTOR2I &aPt) override
void SetEnd(const VECTOR2I &aEnd) override
void SetStart(const VECTOR2I &aStart) override
void SetBezierC2(const VECTOR2I &aPt) override
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
An abstract shape on 2D plane.
Definition shape.h:124
static void Stroke(const SHAPE *aShape, LINE_STYLE aLineStyle, int aWidth, const KIGFX::RENDER_SETTINGS *aRenderSettings, const std::function< void(const VECTOR2I &a, const VECTOR2I &b)> &aStroker)
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:279
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:411
LINE_STYLE
Dashed line types.
std::vector< double > gaps
std::vector< double > drawn
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
static SHAPE_LINE_CHAIN makeBezierChain()
BOOST_AUTO_TEST_CASE(BezierDashedLineHasGaps)
static DASH_RUNS collectRuns(const SHAPE *aShape, LINE_STYLE aStyle, int aWidth, const KIGFX::RENDER_SETTINGS *aSettings)
VECTOR3I expected(15, 30, 45)
const SHAPE_LINE_CHAIN chain
VECTOR2I end
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682