Beispiel #1
0
void GerberImporter::linear_draw_rectangular_aperture(point_type startpoint, point_type endpoint, coordinate_type width,
                                coordinate_type height, ring_type& ring)
{
    if (startpoint.y() > endpoint.y())
        swap(startpoint, endpoint);
    
    if (startpoint.x() > endpoint.x())
    {
        ring.push_back(point_type(startpoint.x() + width / 2, startpoint.y() + height / 2));
        ring.push_back(point_type(startpoint.x() + width / 2, startpoint.y() - height / 2));
        ring.push_back(point_type(startpoint.x() - width / 2, startpoint.y() - height / 2));
        ring.push_back(point_type(endpoint.x() - width / 2, endpoint.y() - height / 2));
        ring.push_back(point_type(endpoint.x() - width / 2, endpoint.y() + height / 2));
        ring.push_back(point_type(endpoint.x() + width / 2, endpoint.y() + height / 2));
    }
    else
    {
        ring.push_back(point_type(startpoint.x() + width / 2, startpoint.y() - height / 2));
        ring.push_back(point_type(startpoint.x() - width / 2, startpoint.y() - height / 2));
        ring.push_back(point_type(startpoint.x() - width / 2, startpoint.y() + height / 2));
        ring.push_back(point_type(endpoint.x() - width / 2, endpoint.y() + height / 2));
        ring.push_back(point_type(endpoint.x() + width / 2, endpoint.y() + height / 2));
        ring.push_back(point_type(endpoint.x() + width / 2, endpoint.y() - height / 2));
    }

    bg::correct(ring);   
}
Beispiel #2
0
void GerberImporter::linear_draw_circular_aperture(point_type startpoint, point_type endpoint,
                                    coordinate_type radius, unsigned int circle_points, ring_type& ring)
{
    const coordinate_type dx = endpoint.x() - startpoint.x();
    const coordinate_type dy = endpoint.y() - startpoint.y();
    double angle_step;
    double offset;
    
    if (circle_points % 2 == 0)
        ++circle_points;

    if (startpoint.x() > endpoint.x())
        swap(startpoint, endpoint);

    angle_step = 2 * bg::math::pi<double>() / circle_points;
    
    if (dx == 0)
        offset = bg::math::pi<double>();
    else
        offset = atan(dy / dx) + bg::math::pi<double>() / 2;
    
    for (unsigned int i = 0; i < circle_points / 2 + 1; i++)
        ring.push_back(point_type(cos(angle_step * i + offset) * radius + startpoint.x(),
                               sin(angle_step * i + offset) * radius + startpoint.y()));

    offset += bg::math::pi<double>();

    for (unsigned int i = 0; i < circle_points / 2 + 1; i++)
        ring.push_back(point_type(cos(angle_step * i + offset) * radius + endpoint.x(),
                               sin(angle_step * i + offset) * radius + endpoint.y()));
    
    bg::correct(ring);
}
Beispiel #3
0
void GerberImporter::draw_rectangle(point_type point1, point_type point2, coordinate_type height, polygon_type& polygon)
{
    const double angle = atan2(point2.y() - point1.y(), point2.x() - point1.x());
    const coordinate_type dx = height / 2 * sin(angle);
    const coordinate_type dy = height / 2 * cos(angle);

    polygon.outer().push_back(point_type(point1.x() + dx, point1.y() - dy));
    polygon.outer().push_back(point_type(point1.x() - dx, point1.y() + dy));
    polygon.outer().push_back(point_type(point2.x() - dx, point2.y() + dy));
    polygon.outer().push_back(point_type(point2.x() + dx, point2.y() - dy));
    polygon.outer().push_back(polygon.outer().front());
    
    bg::correct(polygon);
}
Beispiel #4
0
void GerberImporter::circular_arc(point_type center, coordinate_type radius,
                    double angle1, double angle2, unsigned int circle_points,
                    linestring_type& linestring)
{
    const unsigned int steps = ceil((angle2 - angle1) / (2 * bg::math::pi<double>()) * circle_points);
    const double angle_step = (angle2 - angle1) / steps;
    
    for (unsigned int i = 0; i < steps; i++)
    {
        const double angle = angle1 + i * angle_step;

        linestring.push_back(point_type(cos(angle) * radius + center.x(),
                                        sin(angle) * radius + center.y()));
    }
    
    linestring.push_back(point_type(cos(angle2) * radius + center.x(),
                                    sin(angle2) * radius + center.y()));
}
Beispiel #5
0
void GerberImporter::draw_rectangle(point_type center, coordinate_type width, coordinate_type height,
                                    coordinate_type hole_diameter, unsigned int circle_points, polygon_type& polygon)
{
    const coordinate_type x = center.x();
    const coordinate_type y = center.y();

    polygon.outer().push_back(point_type(x - width / 2, y - height / 2));
    polygon.outer().push_back(point_type(x - width / 2, y + height / 2));
    polygon.outer().push_back(point_type(x + width / 2, y + height / 2));
    polygon.outer().push_back(point_type(x + width / 2, y - height / 2));
    polygon.outer().push_back(polygon.outer().front());
    
    if (hole_diameter != 0)
    {
        polygon.inners().resize(1);
        draw_regular_polygon(center, hole_diameter, circle_points, 0, false, polygon.inners().front());
    }
}
Beispiel #6
0
void GerberImporter::draw_regular_polygon(point_type center, coordinate_type diameter, unsigned int vertices,
                            coordinate_type offset, bool clockwise, ring_type& ring)
{
    double angle_step;
    
    if (clockwise)
        angle_step = -2 * bg::math::pi<double>() / vertices;
    else
        angle_step = 2 * bg::math::pi<double>() / vertices;

    offset *= bg::math::pi<double>() / 180.0;

    for (unsigned int i = 0; i < vertices; i++)
       ring.push_back(point_type(cos(angle_step * i + offset) * diameter / 2 + center.x(),
                        sin(angle_step * i + offset) * diameter / 2 + center.y()));

    ring.push_back(ring.front());
}
shared_ptr<multi_polygon_type> Voronoi::build_voronoi(const multi_polygon_type& input,
                                coordinate_type bounding_box_offset, coordinate_type max_dist)
{
    auto output = make_shared<multi_polygon_type>();
    voronoi_diagram_type voronoi_diagram;
    voronoi_builder_type voronoi_builder;
    vector<segment_type_p> segments;
    list<const cell_type *> visited_cells;
    size_t segments_num = 0;
    ring_type bounding_box_ring;

    bg::assign(bounding_box_ring, bg::return_buffer<box_type>(
                                bg::return_envelope<box_type>(input), bounding_box_offset));

    for (const polygon_type& polygon : input)
    {
        segments_num += polygon.outer().size() - 1;
        
        for (const ring_type& ring : polygon.inners())
        {
            segments_num += ring.size() - 1;
        }
    }
    
    segments_num += bounding_box_ring.size() - 1;
    
    segments.reserve(segments_num);
    
    for (const polygon_type& polygon : input)
    {
        copy_ring(polygon.outer(), segments);

        for (const ring_type& ring : polygon.inners())
        {
            copy_ring(ring, segments);
        }
    }
    
    copy_ring(bounding_box_ring, segments);

    output->resize(input.size());
    for (size_t i = 0; i < input.size(); i++)
        (*output)[i].inners().resize(input.at(i).inners().size());

    boost::polygon::insert(segments.begin(), segments.end(), &voronoi_builder);
    voronoi_builder.construct(&voronoi_diagram);

    for (const cell_type& cell : voronoi_diagram.cells())
    {
        if (!cell.is_degenerate())
        {
            const edge_type *edge = cell.incident_edge();
            const cell_type *last_cell = NULL;
            const auto found_cell = std::find(visited_cells.begin(), visited_cells.end(), &cell);

            bool backwards = false;

            if (found_cell == visited_cells.end())
            {
                pair<const polygon_type *, ring_type *> related_geometries = find_ring(input, cell, *output);
                
                if (related_geometries.first && related_geometries.second)
                {
                    const polygon_type& polygon = *(related_geometries.first);
                    ring_type& ring = *(related_geometries.second);

                    do {
                        if (edge->is_primary())
                        {
                            if (edge->is_finite())
                            {
                                const point_type startpoint (edge->vertex0()->x(), edge->vertex0()->y());
                                const point_type endpoint (edge->vertex1()->x(), edge->vertex1()->y());
                                auto append_remove_extra = [&] (const point_type& point)
                                {
                                    /* 
                                     * This works, but it seems more a workaround than a proper solution.
                                     * Why are these segments here in the first place? FIXME
                                     */
                                    if (ring.size() >= 2 && bg::equals(point, *(ring.end() - 2)))
                                        ring.pop_back();
                                    else 
                                        ring.push_back(point);
                                };

                                if (bg::covered_by(startpoint, polygon) && bg::covered_by(endpoint, polygon))
                                {
                                    ring.clear();
                                    break;
                                }

                                if (ring.empty() || startpoint.x() != ring.back().x() || startpoint.y() != ring.back().y())
                                    append_remove_extra(startpoint);

                                if (edge->is_linear())
                                    append_remove_extra(endpoint);
                                else
                                {
                                    vector<point_type_fp_p> sampled_edge;

                                    sample_curved_edge(edge, segments, sampled_edge, max_dist);

                                    for (auto iterator = sampled_edge.begin() + 1; iterator != sampled_edge.end(); iterator++)
                                        append_remove_extra(point_type(iterator->x(), iterator->y()));
                                }

                            }
                            else
                            {
                                ring.clear();
                                break;
                            }
                        }
                        else
                        {
                            if (!backwards)
                            {
                                const cell_type *current_cell = edge->cell();
                                const cell_type *next_cell = edge->twin()->cell();

                                if (next_cell == last_cell)
                                    backwards = true;
                                else
                                    if (current_cell != &cell)
                                        visited_cells.push_front(current_cell);

                                last_cell = current_cell;
                            }
                            
                            edge = edge->twin();
                        }

                        edge = edge->next();
                    } while (edge != cell.incident_edge());
                }
            }
            else
                visited_cells.erase(found_cell);
        }
    }
    
    bg::correct(*output);
    return output;
}
Beispiel #8
0
 static inline void set(point_type& p, CoordinateType const& value)
 {
     p.y(value);
 }
Beispiel #9
0
 static inline CoordinateType get(point_type const& p)
 {
     return p.y();
 }
 bool operator()(const point_type& a, const point_type& b) const {
   return std::tie(a.x(), a.y()) < std::tie(b.x(), b.y());
 }
Beispiel #11
0
void GerberImporter::draw_oval(point_type center, coordinate_type width, coordinate_type height,
                                coordinate_type hole_diameter, unsigned int circle_points, polygon_type& polygon)
{
    double angle_step;
    double offset;
    coordinate_type x;
    coordinate_type y;
    coordinate_type radius;
    
    if (circle_points % 2 == 0)
        ++circle_points;
    
    angle_step = -2 * bg::math::pi<double>() / circle_points;
    
    if (width < height)
    {
        radius = width / 2;
        offset = 0;
        x = 0;
        y = height / 2 - radius;
    }
    else
    {
        radius = height / 2;
        offset = -bg::math::pi<double>() / 2;
        x = width / 2 - radius;
        y = 0;
    }
    
    for (unsigned int i = 0; i < circle_points / 2 + 1; i++)
        polygon.outer().push_back(point_type(cos(angle_step * i + offset) * radius + center.x() - x,
                                                sin(angle_step * i + offset) * radius + center.y() - y));

    offset += bg::math::pi<double>();

    for (unsigned int i = 0; i < circle_points / 2 + 1; i++)
        polygon.outer().push_back(point_type(cos(angle_step * i + offset) * radius + center.x() + x,
                                                sin(angle_step * i + offset) * radius + center.y() + y));

    polygon.outer().push_back(polygon.outer().front());

    if (hole_diameter != 0)
    {
        polygon.inners().resize(1);
        draw_regular_polygon(center, hole_diameter, circle_points, 0, false, polygon.inners().front());
    }
}
Beispiel #12
0
unique_ptr<multi_polygon_type> GerberImporter::render(bool fill_closed_lines, unsigned int points_per_circle)
{
    map<int, multi_polygon_type> apertures_map;
    ring_type region;
    coordinate_type cfactor;
    unique_ptr<multi_polygon_type> temp_mpoly (new multi_polygon_type());
    bool contour = false;

    vector<pair<const gerbv_layer_t *, gerberimporter_layer> >layers (1);

    auto layers_equivalent = [](const gerbv_layer_t * const layer1, const gerbv_layer_t * const layer2)
    {
        const gerbv_step_and_repeat_t& sr1 = layer1->stepAndRepeat;
        const gerbv_step_and_repeat_t& sr2 = layer2->stepAndRepeat;
    
        if (layer1->polarity == layer2->polarity &&
            sr1.X == sr2.X &&
            sr1.Y == sr2.Y &&
            sr1.dist_X == sr2.dist_X &&
            sr1.dist_Y == sr2.dist_Y)
            return true;
        else
            return false;
    };

    gerbv_image_t *gerber = project->file[0]->image;

    if (gerber->info->polarity != GERBV_POLARITY_POSITIVE)
        unsupported_polarity_throw_exception();

    if (gerber->netlist->state->unit == GERBV_UNIT_MM)
        cfactor = scale / 25.4;
    else
        cfactor = scale;

    layers.front().first = gerber->netlist->layer;

    generate_apertures_map(gerber->aperture, apertures_map, points_per_circle, cfactor);

    for (gerbv_net_t *currentNet = gerber->netlist; currentNet; currentNet = currentNet->next){

        const point_type start (currentNet->start_x * cfactor, currentNet->start_y * cfactor);
        const point_type stop (currentNet->stop_x * cfactor, currentNet->stop_y * cfactor);
        const double * const parameters = gerber->aperture[currentNet->aperture]->parameter;
        multi_polygon_type mpoly;

        if (!layers_equivalent(currentNet->layer, layers.back().first))
        {
            layers.resize(layers.size() + 1);
            layers.back().first = currentNet->layer;
        }

        map<coordinate_type, multi_linestring_type>& paths = layers.back().second.paths;
        unique_ptr<multi_polygon_type>& draws = layers.back().second.draws;

        auto merge_ring = [&](ring_type& ring)
        {
            if (ring.size() > 1)
            {
                polygon_type polygon;
                bg::correct(ring);
                
                if (simplify_cutins(ring, polygon))
                    bg::union_(*draws, polygon, *temp_mpoly);
                else
                    bg::union_(*draws, ring, *temp_mpoly);

                ring.clear();
                draws.swap(temp_mpoly);
                temp_mpoly->clear();
            }
        };

        auto merge_mpoly = [&](multi_polygon_type& mpoly)
        {
            bg::correct(mpoly);
            bg::union_(*draws, mpoly, *temp_mpoly);
            mpoly.clear();
            draws.swap(temp_mpoly);
            temp_mpoly->clear();
        };

        if (currentNet->interpolation == GERBV_INTERPOLATION_LINEARx1) {
        
            if (currentNet->aperture_state == GERBV_APERTURE_STATE_ON) {
            
                if (contour)
                {
                    if (region.empty())
                        bg::append(region, start);

                    bg::append(region, stop);
                }
                else
                {
                    if (gerber->aperture[currentNet->aperture]->type == GERBV_APTYPE_CIRCLE)
                    {
                        linestring_type new_segment;
                        
                        new_segment.push_back(start);
                        new_segment.push_back(stop);
                        
                        merge_paths(paths[coordinate_type(gerber->aperture[currentNet->aperture]->parameter[0] * cfactor / 2)], new_segment);
                    }
                    else if (gerber->aperture[currentNet->aperture]->type == GERBV_APTYPE_RECTANGLE)
                    {
                        mpoly.resize(1);
                        linear_draw_rectangular_aperture(start, stop, parameters[0] * cfactor,
                                                parameters[1] * cfactor, mpoly.back().outer());

                        merge_ring(mpoly.back().outer());
                    }
                    else
                        cerr << "Drawing with an aperture different from a circle "
                                     "or a rectangle is forbidden by the Gerber standard; skipping."
                                  << endl;
                }
            }
            
            else if (currentNet->aperture_state == GERBV_APERTURE_STATE_FLASH) {

                if (contour)
                {
                    cerr << "D03 during contour mode is forbidden by the Gerber "
                                    "standard; skipping" << endl;
                }
                else
                {
                    const auto aperture_mpoly = apertures_map.find(currentNet->aperture);

                    if (aperture_mpoly != apertures_map.end())
                        bg::transform(aperture_mpoly->second, mpoly, translate(stop.x(), stop.y()));
                    else
                        cerr << "Macro aperture " << currentNet->aperture <<
                                    " not found in macros list; skipping" << endl;

                    merge_mpoly(mpoly);
                }
            }
            else if (currentNet->aperture_state == GERBV_APERTURE_STATE_OFF)
            {
                if (contour)
                {
                    if (!region.empty())
                    {
                        bg::append(region, stop);
                        merge_ring(region);
                    }
                }
            }
            else
            {
                cerr << "Unrecognized aperture state: skipping" << endl;
            }
        }
        else if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_START)
        {
            contour = true;
        }
        else if (currentNet->interpolation == GERBV_INTERPOLATION_PAREA_END)
        {
            contour = false;
            
            if (!region.empty())
                merge_ring(region);
        }
        else if (currentNet->interpolation == GERBV_INTERPOLATION_CW_CIRCULAR ||
                 currentNet->interpolation == GERBV_INTERPOLATION_CCW_CIRCULAR)
        {
            if (currentNet->aperture_state == GERBV_APERTURE_STATE_ON) {
                const gerbv_cirseg_t * const cirseg = currentNet->cirseg;
                linestring_type path;

                if (cirseg != NULL)
                {
                    double angle1;
                    double angle2;

                    if (currentNet->interpolation == GERBV_INTERPOLATION_CCW_CIRCULAR)
                    {
                        angle1 = cirseg->angle1;
                        angle2 = cirseg->angle2;
                    }
                    else
                    {
                        angle1 = cirseg->angle2;
                        angle2 = cirseg->angle1;
                    }

                    circular_arc(point_type(cirseg->cp_x * scale, cirseg->cp_y * scale),
                                    cirseg->width * scale / 2,
                                    angle1 * bg::math::pi<double>() / 180.0,
                                    angle2 * bg::math::pi<double>() / 180.0,
                                    points_per_circle,
                                    path);

                    if (contour)
                    {
                        if (region.empty())
                            copy(path.begin(), path.end(), region.end());
                        else
                            copy(path.begin() + 1, path.end(), region.end());
                    }
                    else
                    {
                        if (gerber->aperture[currentNet->aperture]->type == GERBV_APTYPE_CIRCLE)
                            merge_paths(paths[coordinate_type(gerber->aperture[currentNet->aperture]->parameter[0] * cfactor / 2)], path);
                        else
                            cerr << "Drawing an arc with an aperture different from a circle "
                                         "is forbidden by the Gerber standard; skipping."
                                      << endl;
                    }
                }
                else
                    cerr << "Circular arc requested but cirseg == NULL" << endl;
            }
            else if (currentNet->aperture_state == GERBV_APERTURE_STATE_FLASH) {
                cerr << "D03 during circular arc mode is forbidden by the Gerber "
                                "standard; skipping" << endl;
            }
        }
        else if (currentNet->interpolation == GERBV_INTERPOLATION_x10 ||
                 currentNet->interpolation == GERBV_INTERPOLATION_LINEARx01 || 
                 currentNet->interpolation == GERBV_INTERPOLATION_LINEARx001 ) {
            cerr << "Linear zoomed interpolation modes are not supported "
                         "(are them in the RS274X standard?)" << endl;
        }
        else //if (currentNet->interpolation != GERBV_INTERPOLATION_DELETED)
        {
            cerr << "Unrecognized interpolation mode" << endl;
        }
    }

    for (pair<const gerbv_layer_t *, gerberimporter_layer>& layer : layers)
    {
        for (pair<const coordinate_type, multi_linestring_type>& path : layer.second.paths)
        {
            simplify_paths(path.second);
        }
    }

    return generate_layers(layers, fill_closed_lines, cfactor, points_per_circle);
}