KiCad PCB EDA Suite
Loading...
Searching...
No Matches
distribute.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 (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <geometry/distribute.h>
21
22#include <math/vector2d.h>
23
24
25std::vector<int> GetDeltasForDistributeByGaps(const std::vector<std::pair<int, int>>& aItemExtents)
26{
27 std::vector<int> deltas(aItemExtents.size(), 0);
28
29 // This only makes sense for 3 or more items
30 if (aItemExtents.size() < 3)
31 return deltas;
32
33 // The space between the first and last items' inner edges
34 const int totalSpace = aItemExtents.back().first - aItemExtents.front().second;
35 int totalGap = totalSpace;
36
37 for( size_t i = 1; i < aItemExtents.size() - 1; ++i )
38 {
39 const auto& [start, end] = aItemExtents[i];
40 totalGap -= end - start;
41 }
42
43 const double perItemGap = totalGap / double( aItemExtents.size() - 1 );
44
45 // Start counting at the end of the first item
46 int targetPos = aItemExtents.begin()->second;
47
48 // End-cap items don't need to be changed
49 for( size_t i = 1; i < aItemExtents.size() - 1; ++i )
50 {
51 const auto& [start, end] = aItemExtents[i];
52
53 // Take care not to stack rounding errors by keeping the integer accumulator
54 // separate and always re-multiplying the gap
55 const double accumulatedGaps = i * perItemGap;
56 const int delta = targetPos - start + KiROUND(accumulatedGaps);
57
58 deltas[i] = delta;
59
60 // Step over one item span (width or height)
61 targetPos += end - start;
62 }
63
64 return deltas;
65}
66
67std::vector<int> GetDeltasForDistributeByPoints( const std::vector<int>& aItemPositions )
68{
69 std::vector<int> deltas(aItemPositions.size(), 0);
70
71 // This only makes sense for 3 or more items
72 if (aItemPositions.size() < 3)
73 return deltas;
74
75 const int startPos = aItemPositions.front();
76 const int totalGaps = aItemPositions.back() - startPos;
77 const double itemGap = totalGaps / double( aItemPositions.size() - 1 );
78
79 // End-cap items don't need to be changed
80 for( size_t i = 1; i < aItemPositions.size() - 1; ++i )
81 {
82 const int targetPos = startPos + KiROUND( i * itemGap );
83 const int delta = targetPos - aItemPositions[i];
84
85 deltas[i] = delta;
86 }
87
88 return deltas;
89}
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
std::vector< int > GetDeltasForDistributeByGaps(const std::vector< std::pair< int, int > > &aItemExtents)
Given a list of 'n' item spans (e.g.
Definition: distribute.cpp:25
std::vector< int > GetDeltasForDistributeByPoints(const std::vector< int > &aItemPositions)
Definition: distribute.cpp:67
constexpr int delta