Esempio n. 1
0
void GerberImporter::merge_paths(multi_linestring_type &destination, const linestring_type& source)
{
    if (!destination.empty())
    {
        multi_linestring_type::reverse_iterator ls;

        for (ls = destination.rbegin(); ls != destination.rend(); ls++)
        {
            if (bg::equals(ls->back(), source.front()))
            {
                ls->insert(ls->end(), source.begin() + 1, source.end());
                break;
            }
            else if (bg::equals(ls->back(), source.back()))
            {
                ls->insert(ls->end(), source.rbegin() + 1, source.rend());
                break;
            }

            /*
             * The following two cases does not happen very often, and they
             * usually happen when the size of destination is small (often 2),
             * therefore there shouldn't be the need to replace a standard
             * linestring_type (std::vector) with a std::deque
             */
            else if (bg::equals(ls->front(), source.front()))
            {
                reverse(ls->begin(), ls->end());
                ls->insert(ls->end(), source.begin() + 1, source.end());
                break;
            }
            else if (bg::equals(ls->front(), source.back()))
            {
                reverse(ls->begin(), ls->end());
                ls->insert(ls->end(), source.rbegin() + 1, source.rend());
                break;
            }
        }

        if (ls == destination.rend())
        {
            destination.push_back(source);
        }
    }
    else
    {
        destination.push_back(source);
    }
}
Esempio n. 2
0
void GerberImporter::simplify_paths(multi_linestring_type &paths)
{
    for (auto path1 = paths.begin(); path1 != paths.end(); path1++)
    {
        if (!path1->empty())
        {
            for (auto path2 = paths.begin(); path2 != paths.end(); path2++)
            {
                if (!path2->empty() && path1 != path2)
                {
                    if (bg::equals(path1->back(), path2->front()))
                    {
                        path1->insert(path1->end(),
                                      make_move_iterator(next(path2->begin())),
                                      make_move_iterator(path2->end()));

                        path2->clear();
                    }
                    else if (bg::equals(path1->back(), path2->back()))
                    {
                        if (path1->size() < path2->size())
                        {
                            path2->insert(path2->end(),
                                          make_move_iterator(next(path1->rbegin())),
                                          make_move_iterator(path1->rend()));
                            path1->swap(*path2);
                        }
                        else
                            path1->insert(path1->end(),
                                          make_move_iterator(next(path2->rbegin())),
                                          make_move_iterator(path2->rend()));

                        path2->clear();
                    }
                    else if (bg::equals(path1->front(), path2->back()))
                    {
                        path2->insert(path2->end(),
                                      make_move_iterator(next(path1->begin())),
                                      make_move_iterator(path1->end()));
                        path1->swap(*path2);

                        path2->clear();
                    }
                    else if (bg::equals(path1->front(), path2->front()))
                    {
                        std::reverse(path1->begin(), path1->end());
                        path1->insert(path1->end(),
                                      make_move_iterator(next(path2->begin())),
                                      make_move_iterator(path2->end()));

                        path2->clear();
                    }
                }
            }
        }
    }

    auto isEmpty = [&](const linestring_type& ls)
    {
        return ls.empty();
    };

    paths.erase(std::remove_if(paths.begin(), paths.end(), isEmpty), paths.end());
}
Esempio n. 3
0
unique_ptr<vector<polygon_type> > Surface_vectorial::offset_polygon(const multi_polygon_type& input,
                            const multi_polygon_type_fp& voronoi_polygons, multi_linestring_type& toolpath,
                            bool& contentions, coordinate_type offset, size_t index,
                            unsigned int steps, bool do_voronoi)
{
    unique_ptr<vector<polygon_type> > polygons (new vector<polygon_type>(steps));
    list<list<const ring_type *> > rings (steps);
    auto ring_i = rings.begin();
    point_type last_point;

    auto push_point = [&](const point_type& point)
    {
        toolpath.back().push_back(point);
    };

    auto copy_ring_to_toolpath = [&](const ring_type& ring, unsigned int start)
    {
        const auto size_minus_1 = ring.size() - 1;
        unsigned int i = start;

        do
        {
            push_point(ring[i]);
            i = (i + 1) % size_minus_1;
        } while (i != start);

        push_point(ring[i]);
        last_point = ring[i];
    };

    auto find_first_nonempty = [&]()
    {
        for (auto i = rings.begin(); i != rings.end(); i++)
            if (!i->empty())
                return i;
        return rings.end();
    };

    auto find_closest_point_index = [&](const ring_type& ring)
    {
        const unsigned int size = ring.size();
        auto min_distance = bg::comparable_distance(ring[0], last_point);
        unsigned int index = 0;

        for (unsigned int i = 1; i < size; i++)
        {
            const auto distance = bg::comparable_distance(ring[i], last_point);

            if (distance < min_distance)
            {
                min_distance = distance;
                index = i;
            }
        }

        return index;
    };

    toolpath.push_back(linestring_type());

    bool outer_collapsed = false;

    for (unsigned int i = 0; i < steps; i++)
    {
        coordinate_type expand_by;
        if (!do_voronoi) {
            // Number of rings is the same as the number of steps.
            expand_by = offset * (i+1);
        } else {
            // Voronoi lines are on the boundary and shared between
            // multi_polygons so we only need half as many of them.
            double factor = ((1-double(steps))/2 + i);
            if (factor > 0) {
                continue; // Don't need it.
            }
            expand_by = offset * factor;
        }
        multi_polygon_type integral_voronoi_polygons;
        bg::convert(voronoi_polygons, integral_voronoi_polygons);
        polygon_type masked_milling_poly = do_voronoi ? integral_voronoi_polygons[index] : input[index];
        multi_polygon_type masked_milling_polys;
        if (mask) {
            bg::intersection(masked_milling_poly, *(mask->vectorial_surface), masked_milling_polys);
        } else {
            bg::convert(masked_milling_poly, masked_milling_polys);
        }
        if (expand_by == 0)
        {
            (*polygons)[i] = masked_milling_polys[0];
        }
        else
        {
            multi_polygon_type_fp mpoly_temp_fp;
            polygon_type_fp input_fp;
            bg::convert(masked_milling_polys[0], input_fp);

            // Buffer should be done on floating point polygons.
            bg::buffer(input_fp, mpoly_temp_fp,
                       bg::strategy::buffer::distance_symmetric<coordinate_type>(expand_by),
                       bg::strategy::buffer::side_straight(),
                       bg::strategy::buffer::join_round(points_per_circle),
                       //bg::strategy::buffer::join_miter(numeric_limits<coordinate_type>::max()),
                       bg::strategy::buffer::end_flat(),
                       bg::strategy::buffer::point_circle(30));

            auto mpoly_fp = make_shared<multi_polygon_type_fp>();
            if (!do_voronoi) {
                bg::intersection(mpoly_temp_fp[0], voronoi_polygons[index], *mpoly_fp);
            } else {
                polygon_type_fp min_shape;
                bg::convert(input[index], min_shape);
                bg::union_(mpoly_temp_fp[0], min_shape, *mpoly_fp);
            }
            bg::convert((*mpoly_fp)[0], (*polygons)[i]);

            if (!bg::equals((*mpoly_fp)[0], mpoly_temp_fp[0]))
                contentions = true;
        }

        if (i == 0)
            copy_ring_to_toolpath((*polygons)[i].outer(), 0);
        else
        {
            if (!outer_collapsed && bg::equals((*polygons)[i].outer(), (*polygons)[i - 1].outer()))
                outer_collapsed = true;

            if (!outer_collapsed)
                copy_ring_to_toolpath((*polygons)[i].outer(), find_closest_point_index((*polygons)[i].outer()));
        }

        for (const ring_type& ring : (*polygons)[i].inners())
            ring_i->push_back(&ring);
        
        ++ring_i;
    }

    ring_i = find_first_nonempty();

    while (ring_i != rings.end())
    {
        const ring_type *biggest = ring_i->front();
        const ring_type *prev = biggest;
        auto ring_j = next(ring_i);

        toolpath.push_back(linestring_type());
        copy_ring_to_toolpath(*biggest, 0);

        while (ring_j != rings.end())
        {
            list<const ring_type *>::iterator j;

            for (j = ring_j->begin(); j != ring_j->end(); j++)
            {
                if (bg::equals(**j, *prev))
                {
                    ring_j->erase(j);
                    break;
                }
                else
                {
                    if (bg::covered_by(**j, *prev))
                    {
                        auto index = find_closest_point_index(**j);
                        ring_type ring (prev->rbegin(), prev->rend());
                        linestring_type segment;

                        segment.push_back((**j)[index]);
                        segment.push_back(last_point);

                        if (bg::covered_by(segment, ring))
                        {
                            copy_ring_to_toolpath(**j, index);
                            prev = *j;
                            ring_j->erase(j);
                            break;
                        }
                    }
                }
            }

            if (j == ring_j->end())
                ring_j = rings.end();
            else
                ++ring_j;
        }

        ring_i->erase(ring_i->begin());
        ring_i = find_first_nonempty();
    }

    return polygons;
}