Welcome to mirror list, hosted at ThFree Co, Russian Federation.

geometries_nfp.hpp « libnest2d « libnest2d « src « xs - github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 9f8bd603147b793aa0dabeac23f7ac65026baf1f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#ifndef GEOMETRIES_NOFITPOLYGON_HPP
#define GEOMETRIES_NOFITPOLYGON_HPP

#include "geometry_traits.hpp"
#include <algorithm>
#include <vector>

namespace libnest2d {

struct Nfp {

template<class RawShape>
using Shapes = typename ShapeLike::Shapes<RawShape>;

template<class RawShape>
static RawShape& minkowskiAdd(RawShape& sh, const RawShape& /*other*/)
{
    static_assert(always_false<RawShape>::value,
                  "Nfp::minkowskiAdd() unimplemented!");
    return sh;
}

template<class RawShape>
static Shapes<RawShape> merge(const Shapes<RawShape>& shc, const RawShape& sh)
{
    static_assert(always_false<RawShape>::value,
                  "Nfp::merge(shapes, shape) unimplemented!");
}

template<class RawShape>
inline static TPoint<RawShape> referenceVertex(const RawShape& sh)
{
    return rightmostUpVertex(sh);
}

template<class RawShape>
static TPoint<RawShape> leftmostDownVertex(const RawShape& sh) {

    // find min x and min y vertex
    auto it = std::min_element(ShapeLike::cbegin(sh), ShapeLike::cend(sh),
                               _vsort<RawShape>);

    return *it;
}

template<class RawShape>
static TPoint<RawShape> rightmostUpVertex(const RawShape& sh) {

    // find min x and min y vertex
    auto it = std::max_element(ShapeLike::cbegin(sh), ShapeLike::cend(sh),
                               _vsort<RawShape>);

    return *it;
}

template<class RawShape>
static RawShape noFitPolygon(const RawShape& sh, const RawShape& other) {
    auto isConvex = [](const RawShape& sh) {

        return true;
    };

    using Vertex = TPoint<RawShape>;
    using Edge = _Segment<Vertex>;

    auto nfpConvexConvex = [] (
            const RawShape& sh,
            const RawShape& cother)
    {
        RawShape other = cother;

        // Make the other polygon counter-clockwise
        std::reverse(ShapeLike::begin(other), ShapeLike::end(other));

        RawShape rsh;   // Final nfp placeholder
        std::vector<Edge> edgelist;

        size_t cap = ShapeLike::contourVertexCount(sh) +
                ShapeLike::contourVertexCount(other);

        // Reserve the needed memory
        edgelist.reserve(cap);
        ShapeLike::reserve(rsh, cap);

        { // place all edges from sh into edgelist
            auto first = ShapeLike::cbegin(sh);
            auto next = first + 1;
            auto endit = ShapeLike::cend(sh);

            while(next != endit) edgelist.emplace_back(*(first++), *(next++));
        }

        { // place all edges from other into edgelist
            auto first = ShapeLike::cbegin(other);
            auto next = first + 1;
            auto endit = ShapeLike::cend(other);

            while(next != endit) edgelist.emplace_back(*(first++), *(next++));
        }

        // Sort the edges by angle to X axis.
        std::sort(edgelist.begin(), edgelist.end(),
                  [](const Edge& e1, const Edge& e2)
        {
            return e1.angleToXaxis() > e2.angleToXaxis();
        });

        // Add the two vertices from the first edge into the final polygon.
        ShapeLike::addVertex(rsh, edgelist.front().first());
        ShapeLike::addVertex(rsh, edgelist.front().second());

        auto tmp = std::next(ShapeLike::begin(rsh));

        // Construct final nfp by placing each edge to the end of the previous
        for(auto eit = std::next(edgelist.begin());
            eit != edgelist.end();
            ++eit)
        {
            auto d = *tmp - eit->first();
            auto p = eit->second() + d;

            ShapeLike::addVertex(rsh, p);

            tmp = std::next(tmp);
        }

        // Now we have an nfp somewhere in the dark. We need to get it
        // to the right position around the stationary shape.
        // This is done by choosing the leftmost lowest vertex of the
        // orbiting polygon to be touched with the rightmost upper
        // vertex of the stationary polygon. In this configuration, the
        // reference vertex of the orbiting polygon (which can be dragged around
        // the nfp) will be its rightmost upper vertex that coincides with the
        // rightmost upper vertex of the nfp. No proof provided other than Jonas
        // Lindmark's reasoning about the reference vertex of nfp in his thesis
        // ("No fit polygon problem" - section 2.1.9)

        auto csh = sh;  // Copy sh, we will sort the verices in the copy
        auto& cmp = _vsort<RawShape>;
        std::sort(ShapeLike::begin(csh), ShapeLike::end(csh), cmp);
        std::sort(ShapeLike::begin(other), ShapeLike::end(other), cmp);

        // leftmost lower vertex of the stationary polygon
        auto& touch_sh = *(std::prev(ShapeLike::end(csh)));
        // rightmost upper vertex of the orbiting polygon
        auto& touch_other = *(ShapeLike::begin(other));

        // Calculate the difference and move the orbiter to the touch position.
        auto dtouch = touch_sh - touch_other;
        auto top_other = *(std::prev(ShapeLike::end(other))) + dtouch;

        // Get the righmost upper vertex of the nfp and move it to the RMU of
        // the orbiter because they should coincide.
        auto&& top_nfp = rightmostUpVertex(rsh);
        auto dnfp = top_other - top_nfp;
        std::for_each(ShapeLike::begin(rsh), ShapeLike::end(rsh),
                      [&dnfp](Vertex& v) { v+= dnfp; } );

        return rsh;
    };

    RawShape rsh;

    enum e_dispatch {
        CONVEX_CONVEX,
        CONCAVE_CONVEX,
        CONVEX_CONCAVE,
        CONCAVE_CONCAVE
    };

    int sel = isConvex(sh) ? CONVEX_CONVEX : CONCAVE_CONVEX;
    sel += isConvex(other) ? CONVEX_CONVEX : CONVEX_CONCAVE;

    switch(sel) {
    case CONVEX_CONVEX:
        rsh = nfpConvexConvex(sh, other); break;
    case CONCAVE_CONVEX:
        break;
    case CONVEX_CONCAVE:
        break;
    case CONCAVE_CONCAVE:
        break;
    }

    return rsh;
}

template<class RawShape>
static inline Shapes<RawShape> noFitPolygon(const Shapes<RawShape>& shapes,
                                            const RawShape& other)
{
    assert(shapes.size() >= 1);
    auto shit = shapes.begin();

    Shapes<RawShape> ret;
    ret.emplace_back(noFitPolygon(*shit, other));

    while(++shit != shapes.end()) ret = merge(ret, noFitPolygon(*shit, other));

    return ret;
}

private:

// Do not specialize this...
template<class RawShape>
static inline bool _vsort(const TPoint<RawShape>& v1,
                          const TPoint<RawShape>& v2)
{
    using Coord = TCoord<TPoint<RawShape>>;
    auto diff = getY(v1) - getY(v2);
    if(std::abs(diff) <= std::numeric_limits<Coord>::epsilon())
        return getX(v1) < getX(v2);

    return diff < 0;
}

};

}

#endif // GEOMETRIES_NOFITPOLYGON_HPP