Index: trunk/src/route.c =================================================================== --- trunk/src/route.c (nonexistent) +++ trunk/src/route.c (revision 7704) @@ -0,0 +1,592 @@ +/* + * COPYRIGHT + * + * PCB, interactive printed circuit board design + * Copyright (C) 1994,1995,1996, 2004 Thomas Nau + * Copyright (C) 2017 Adrian Purser + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Contact addresses for paper mail and Email: + * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany + * Thomas.Nau@rz.uni-ulm.de + * + */ +#include "config.h" +#include "conf_core.h" +#include "math_helper.h" +#include "board.h" +#include "data.h" +#include "find.h" +#include "rtree.h" +#include "route.h" + +void +pcb_route_init(pcb_route_t * p_route) +{ + p_route->size = 0; + p_route->capacity = ROUTE_SMALL_DATA_SIZE; + p_route->objects = &p_route->small_data[0]; +} + +void +pcb_route_destroy(pcb_route_t * p_route) +{ + if(p_route->capacity > ROUTE_SMALL_DATA_SIZE) + free(p_route->objects); + p_route->size = 0; + p_route->capacity = ROUTE_SMALL_DATA_SIZE; + p_route->objects = &p_route->small_data[0]; +} + +void +pcb_route_reset(pcb_route_t * p_route) +{ + /* NOTE: Currently this function just sets the size back to zero. It does not + free any memory used so the capacity will stay the same. + */ + + p_route->size = 0; +} + +void +pcb_route_reserve(pcb_route_t * p_route,int size) +{ + int grow; + + if(size <= p_route->capacity) + return; + + grow = size - p_route->capacity; + if(grow < 8) + grow = 8; + + if(p_route->capacity == ROUTE_SMALL_DATA_SIZE) { + p_route->capacity += grow; + p_route->objects = (pcb_route_object_t *) malloc(p_route->capacity*sizeof(pcb_route_object_t)); + memcpy(p_route->objects,&p_route->small_data[0],p_route->size*sizeof(pcb_route_object_t)); + } + else { + p_route->capacity += grow; + p_route->objects = (pcb_route_object_t *)realloc(p_route->objects,p_route->capacity*sizeof(pcb_route_object_t)); + } +} + +void +pcb_route_resize(pcb_route_t * p_route,int size) +{ + pcb_route_reserve(p_route,size); + p_route->size = size; +} + +pcb_route_object_t * +pcb_route_alloc_object(pcb_route_t * p_route) +{ + pcb_route_resize(p_route,p_route->size+1); + return &p_route->objects[p_route->size-1]; +} + +void +pcb_route_add_line( pcb_route_t * p_route,pcb_point_t * point1,pcb_point_t * point2,pcb_layer_id_t layer ) +{ + pcb_route_object_t * p_object = pcb_route_alloc_object(p_route); + if(p_object == NULL) + return; + + p_object->point1 = *point1; + p_object->point2 = *point2; + p_object->layer = layer; + p_object->type = PCB_TYPE_LINE; +} + +void +pcb_route_add_arc( pcb_route_t * p_route,pcb_point_t * center,pcb_angle_t start_angle,pcb_angle_t delta,pcb_coord_t radius,pcb_layer_id_t layer ) +{ + pcb_route_object_t * p_object = pcb_route_alloc_object(p_route); + if(p_object == NULL) + return; + + p_object->point1 = *center; + p_object->start_angle = start_angle; + p_object->delta_angle = delta; + p_object->radius = radius; + p_object->layer = layer; + p_object->type = PCB_TYPE_ARC; +} + + +void +pcb_route_direct( pcb_route_t * p_route, + pcb_point_t * point1, + pcb_point_t * point2, + pcb_layer_id_t layer, + pcb_coord_t thickness, + pcb_coord_t clearance ) +{ + pcb_route_reset(p_route); + p_route->start_point = *point1; + p_route->end_point = *point2; + p_route->start_layer = layer; + p_route->end_layer = layer; + p_route->thickness = thickness; + p_route->clearance = clearance; + pcb_route_add_line(p_route,point1,point2,layer); +} + +/*----------------------------------------------------------- + * Calculate an arc fitted to a corner. + *---------------------------------------------------------*/ + +void +pcb_route_calculate_corner_arc( const pcb_point_t * point1, + const pcb_point_t * point2, + const pcb_point_t * point3, + double radius, + pcb_route_object_t * p_out_obj, + pcb_point_t * p_endpoint1, + pcb_point_t * p_endpoint2 + ) +{ + const double r_min = 10.0; + + const pcb_coord_t dx1 = point1->X - point2->X; + const pcb_coord_t dy1 = point1->Y - point2->Y; + const pcb_coord_t dx2 = point3->X - point2->X; + const pcb_coord_t dy2 = point3->Y - point2->Y; + + const double angle1 = atan2(dy1, dx1); + const double angle2 = atan2(dy2, dx2); + + const double ad = angle2-angle1; + const double d = ad > M_PI ? ad-(M_PI*2.0) : (ad < -M_PI ? ad + (M_PI * 2.0) : ad); + + const double hangle = fabs(d * 0.5); + const double angle3 = angle1 + (d * 0.5); + + /* Vector from point2 to the other points */ + const double vx1 = cos(angle1); + const double vy1 = sin(angle1); + const double vx2 = cos(angle2); + const double vy2 = sin(angle2); + + /* Distance from point2 to the other points */ + const double l1 = fabs(abs(vx1) > fabs(vy1) ? dx1/vx1 : dy1/vy1); + const double l2 = fabs(abs(vx2) > fabs(vy2) ? dx2/vx2 : dy2/vy2); + + /* Calculate maximum possible radius */ + const double rmax = (l1 < l2 ? l1 : l2) * tan(hangle); + const double r = rmax < radius ? rmax : radius; + + if(r >= r_min) + { + /* Calculate arc center coordinates. */ + const double sh = sin(hangle); + const pcb_coord_t xc = point2->X + (pcb_coord_t)((cos(angle3)*r)/sh); + const pcb_coord_t yc = point2->Y + (pcb_coord_t)((sin(angle3)*r)/sh); + + /* Calculate arc start and delta angles. */ + const double delta = d < 0 ? -(M_PI + d) : M_PI - d; + const double start = (d < 0.0 ? (M_PI * 0.5) - angle1 : ((M_PI * 0.5) - angle2) - delta); + + p_out_obj->point1.X = xc; + p_out_obj->point1.Y = yc; + p_out_obj->start_angle = start * PCB_RAD_TO_DEG; /* Start Angle */ + p_out_obj->delta_angle = delta * PCB_RAD_TO_DEG; /* Delta Angle */ + p_out_obj->radius = r; + + if(p_endpoint1) + { + p_endpoint1->X = xc - (pcb_coord_t)(r * cos(start)); + p_endpoint1->Y = yc + (pcb_coord_t)(r * sin(start)); + } + + if(p_endpoint1) + { + p_endpoint2->X = xc - (pcb_coord_t)(r * cos(start+delta)); + p_endpoint2->Y = yc + (pcb_coord_t)(r * sin(start+delta)); + } + } + else + { + if(p_endpoint1) + *p_endpoint1 = *point2; + + if(p_endpoint2) + *p_endpoint2 = *point2; + } +} + +void +pcb_route_calculate_45(pcb_point_t * start_point, pcb_point_t * target_point) +{ + + pcb_coord_t dx, dy, min; + unsigned direction = 0; + double m; + + /* first calculate direction of line */ + dx = target_point->X - start_point->X; + dy = target_point->Y - start_point->Y; + + if (!dx) { + if (!dy) + /* zero length line, don't draw anything */ + return; + else + direction = dy > 0 ? 0 : 4; + } + else { + m = (double) dy / dx; + direction = 2; + if (m > PCB_TAN_30_DEGREE) + direction = m > PCB_TAN_60_DEGREE ? 0 : 1; + else if (m < -PCB_TAN_30_DEGREE) + direction = m < -PCB_TAN_60_DEGREE ? 0 : 3; + } + + if (dx < 0) + direction += 4; + + dx = coord_abs(dx); + dy = coord_abs(dy); + min = MIN(dx, dy); + + /* now set up the second pair of coordinates */ + switch (direction) + { + case 0: + case 4: + target_point->X = start_point->X; + break; + + case 2: + case 6: + target_point->Y = start_point->Y; + break; + + case 1: + target_point->X = start_point->X + min; + target_point->Y = start_point->Y + min; + break; + + case 3: + target_point->X = start_point->X + min; + target_point->Y = start_point->Y - min; + break; + + case 5: + target_point->X = start_point->X - min; + target_point->Y = start_point->Y - min; + break; + + case 7: + target_point->X = start_point->X - min; + target_point->Y = start_point->Y + min; + break; + } +} + + +/* TODO: Pass in other required information such as object flags */ +void +pcb_route_calculate(pcb_route_t * p_route, + pcb_point_t * point1, + pcb_point_t * point2, + pcb_layer_id_t layer_id, + pcb_coord_t thickness, + pcb_coord_t clearance, + int mod1, + int mod2 ) +{ + + /* TODO: If an external route calculator has been selected then use it instead of this default one. */ + /* TODO: Add DRC Checking */ + + + /* Set radius to 0 for standard 45/90 operation */ + const pcb_coord_t radius = thickness * 4.0; + + /* If the line can be drawn directly to the target then add a single line segment. */ + if(PCB->RatDraw || conf_core.editor.all_direction_lines) { + pcb_route_direct(p_route,point1,point2,layer_id,thickness,clearance); + return; + } + + /* Restart the route */ + pcb_route_reset(p_route); + p_route->start_point = *point1; + p_route->thickness = thickness; + p_route->clearance = clearance; + p_route->start_layer = layer_id; + p_route->end_layer = layer_id; + + /* If Refraction is 0 then add a single line segment that is horizontal, vertical or 45 degrees. + * This line segment might not end under the crosshair. + */ + if(conf_core.editor.line_refraction == 0) { + pcb_point_t target = *point2; + pcb_route_calculate_45(point1,&target); + pcb_route_add_line(p_route,point1,&target,layer_id); + p_route->end_point = target; + } + else { + /* Refraction is non-zero so add multiple lines (horizontal, vertical and/or 45 degrees). */ + pcb_coord_t dx, dy; + pcb_point_t target; + pcb_bool way = (conf_core.editor.line_refraction == 1 ? pcb_false : pcb_true); + + /* swap the 'way' if mod1 is set (typically the shift key)*/ + if(mod1) + way = !way; + + dx = point2->X - point1->X; + dy = point2->Y - point1->Y; + + if (!way) { + if (coord_abs(dx) > coord_abs(dy)) { + target.X = point2->X - SGN(dx) * coord_abs(dy); + target.Y = point1->Y; + } + else { + target.X = point1->X; + target.Y = point2->Y - SGN(dy) * coord_abs(dx); + } + } + else { + if (coord_abs(dx) > coord_abs(dy)) { + target.X = point1->X + SGN(dx) * coord_abs(dy); + target.Y = point2->Y; + } + else { + target.X = point2->X; + target.Y = point1->Y + SGN(dy) * coord_abs(dx);; + } + } + + if(radius > 0.0) { + pcb_route_object_t arc; + pcb_point_t target1; + pcb_point_t target2; + + pcb_route_calculate_corner_arc(point1,&target,point2,radius,&arc,&target1,&target2); + + if((point1->X != target1.X) || (point1->Y != target1.Y)) + pcb_route_add_line(p_route,point1,&target1,layer_id); + + if((target1.X != target2.X) || (target1.Y != target2.Y)) + pcb_route_add_arc(p_route,&arc.point1,arc.start_angle,arc.delta_angle,arc.radius,layer_id); + + if((point2->X != target2.X) || (point2->Y != target2.Y)) + pcb_route_add_line(p_route,&target2,point2,layer_id); + + p_route->end_point = *point2; + } + else { + pcb_route_add_line(p_route,point1,&target,layer_id); + pcb_route_add_line(p_route,&target,point2,layer_id); + p_route->end_point = *point2; + } + } +} + +void +pcb_route_apply(const pcb_route_t * p_route) +{ + + int i; + int applied = 0; + + for( i=0;isize;i++) { + pcb_route_object_t const * p_obj = &p_route->objects[i]; + pcb_layer_t * layer = pcb_get_layer(p_obj->layer); + + switch(p_obj->type) + { + case PCB_TYPE_LINE : + { + pcb_line_t * line = pcb_line_new_merge( layer, + p_obj->point1.X, + p_obj->point1.Y, + p_obj->point2.X, + p_obj->point2.Y, + p_route->thickness, + 2 * p_route->clearance, + pcb_flag_make(PCB_FLAG_CLEARLINE) ); + if(line) { + pcb_added_lines++; + pcb_obj_add_attribs(line, PCB->pen_attr); + pcb_undo_add_obj_to_create(PCB_TYPE_LINE, layer, line, line); + DrawLine(layer, line); + pcb_undo_inc_serial(); + applied = 1; + } + } + break; + + case PCB_TYPE_ARC : + { + pcb_arc_t * arc = pcb_arc_new( layer, + p_obj->point1.X, + p_obj->point1.Y, + p_obj->radius, + p_obj->radius, + p_obj->start_angle, + p_obj->delta_angle, + p_route->thickness, + p_route->clearance, + pcb_flag_make(PCB_FLAG_CLEARLINE) ); + if(arc) { + pcb_added_lines++; + pcb_obj_add_attribs(arc, PCB->pen_attr); + pcb_undo_add_obj_to_create(PCB_TYPE_ARC, layer, arc, arc); + pcb_undo_inc_serial(); + DrawArc(layer, arc); + applied = 1; + } + } + break; + + default : + break; + } + } + +} + +/*============================================================================= + * + * Route Drawing + * + *===========================================================================*/ + +/*----------------------------------------------------------- + * Draws the outline of a line + *---------------------------------------------------------*/ +void +pcb_route_draw_line(pcb_hid_gc_t GC, + pcb_coord_t x1, + pcb_coord_t y1, + pcb_coord_t x2, + pcb_coord_t y2, + pcb_coord_t thickness ) +{ + pcb_coord_t dx = x2 - x1; + pcb_coord_t dy = y2 - y1; + double h = (dx != 0 || dy != 0) ? (0.5 * thickness / sqrt(PCB_SQUARE(dx) + PCB_SQUARE(dy))) : 0.0; + pcb_coord_t ox = dy * h + 0.5 * SGN(dy); + pcb_coord_t oy = -(dx * h + 0.5 * SGN(dx)); + + pcb_gui->draw_line(GC, x1 + ox, y1 + oy, x2 + ox, y2 + oy); + + if (coord_abs(ox) >= pcb_pixel_slop || coord_abs(oy) >= pcb_pixel_slop) { + pcb_angle_t angle = atan2(dx, dy) * 57.295779; + pcb_gui->draw_line(GC, x1 - ox, y1 - oy, x2 - ox, y2 - oy); + pcb_gui->draw_arc(GC, x1, y1, thickness / 2, thickness / 2, angle - 180, 180); + pcb_gui->draw_arc(GC, x2, y2, thickness / 2, thickness / 2, angle, 180); + } +} + +/*----------------------------------------------------------- + * Draws the outline of an arc + *---------------------------------------------------------*/ +void +pcb_route_draw_arc( pcb_hid_gc_t GC, + pcb_coord_t x, + pcb_coord_t y, + pcb_angle_t start_angle, + pcb_angle_t delta, + pcb_coord_t radius, + pcb_coord_t thickness ) +{ + double wid = thickness / 2; + + if(delta < 0) { + start_angle += delta; + delta = -delta; + } + + double x1 = x - (cos(PCB_M180 * start_angle) * radius); + double y1 = y + (sin(PCB_M180 * start_angle) * radius); + double x2 = x - (cos(PCB_M180 * (start_angle+delta)) * radius); + double y2 = y + (sin(PCB_M180 * (start_angle+delta)) * radius); + + pcb_gui->draw_arc(GC, x, y, radius + wid, radius + wid, start_angle, delta); + if (wid > pcb_pixel_slop) { + pcb_gui->draw_arc(GC, x, y, radius - wid, radius - wid, start_angle, delta ); + pcb_gui->draw_arc(GC, x1, y1, wid, wid, start_angle, -180 * SGN(delta) ); + pcb_gui->draw_arc(GC, x2, y2, wid, wid, start_angle + delta, 180 * SGN(delta) ); + } + +} + +/*----------------------------------------------------------- + * Draws the route as outlines + *---------------------------------------------------------*/ +void +pcb_route_draw( pcb_route_t * p_route,pcb_hid_gc_t GC ) +{ + int i=0; + for(i=0;isize;++i) { + const pcb_route_object_t * p_obj = &p_route->objects[i]; + + pcb_layer_t * layer = pcb_get_layer(p_obj->layer); + if(layer) + pcb_gui->set_color(GC,layer->Color); + + switch(p_obj->type) { + case PCB_TYPE_LINE : + pcb_route_draw_line(GC,p_obj->point1.X,p_obj->point1.Y,p_obj->point2.X,p_obj->point2.Y,p_route->thickness); + break; + + case PCB_TYPE_ARC : + pcb_route_draw_arc(GC,p_obj->point1.X,p_obj->point1.Y,p_obj->start_angle,p_obj->delta_angle,p_obj->radius,p_route->thickness); + break; + + default : + break; + } + } +} + +/*----------------------------------------------------------- + * Draws a drc outline around the route + *---------------------------------------------------------*/ +void +pcb_route_draw_drc( pcb_route_t * p_route,pcb_hid_gc_t GC ) +{ + pcb_coord_t thickness = p_route->thickness + 2 * p_route->clearance; + + pcb_gui->set_color(GC,conf_core.appearance.color.cross); + + int i=0; + for(i=0;isize;++i) { + const pcb_route_object_t * p_obj = &p_route->objects[i]; + + switch(p_obj->type) { + case PCB_TYPE_LINE : + pcb_route_draw_line(GC,p_obj->point1.X,p_obj->point1.Y,p_obj->point2.X,p_obj->point2.Y,thickness); + break; + + case PCB_TYPE_ARC : + pcb_route_draw_arc(GC,p_obj->point1.X,p_obj->point1.Y,p_obj->start_angle,p_obj->delta_angle,p_obj->radius,thickness); + break; + + default : + break; + } + } +} + + Index: trunk/src/route.h =================================================================== --- trunk/src/route.h (nonexistent) +++ trunk/src/route.h (revision 7704) @@ -0,0 +1,97 @@ +/* + * COPYRIGHT + * + * PCB, interactive printed circuit board design + * Copyright (C) 1994,1995,1996, 2004 Thomas Nau + * Copyright (C) 2017 Adrian Purser + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Contact addresses for paper mail and Email: + * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany + * Thomas.Nau@rz.uni-ulm.de + * + */ + +#ifndef GUARD_PCB_RND_ROUTE_H +#define GUARD_PCB_RND_ROUTE_H + +#include "const.h" + +#define ROUTE_SMALL_DATA_SIZE 4 + +typedef struct { + pcb_obj_type_t type; + pcb_point_t point1; /* Line: Start Point, Arc: Center Point */ + pcb_point_t point2; /* Line: End Point */ + pcb_coord_t radius; /* Arc */ + pcb_angle_t start_angle; /* Arc */ + pcb_angle_t delta_angle; /* Arc */ + pcb_layer_id_t layer; +} pcb_route_object_t; + +typedef struct { + pcb_point_t start_point; + pcb_point_t end_point; + pcb_coord_t thickness; + pcb_coord_t clearance; + pcb_layer_id_t start_layer; /* The ID of the layer that the route started on */ + pcb_layer_id_t end_layer; /* The ID of the layer that the route ended on, usually the same as the start for simple routes*/ + int size; /* The number of active objects in the array */ + int capacity; /* The size of the object array */ + pcb_route_object_t * objects; /* Pointer to the object array data */ + pcb_route_object_t small_data[ROUTE_SMALL_DATA_SIZE]; /* Small object array used to avoid allocating memory for small routes */ +} pcb_route_t; + + +void pcb_route_init(pcb_route_t * p_route); +void pcb_route_destroy(pcb_route_t * p_route); +void pcb_route_reset(pcb_route_t * p_route); +void pcb_route_reserve(pcb_route_t * p_route,int size); +void pcb_route_resize(pcb_route_t * p_route,int size); + +void pcb_route_add_line( pcb_route_t * p_route, + pcb_point_t * point1, + pcb_point_t * point2, + pcb_layer_id_t layer ); + +void pcb_route_add_arc( pcb_route_t * p_route, + pcb_point_t * center, + pcb_angle_t start_angle, + pcb_angle_t delta, + pcb_coord_t radius, + pcb_layer_id_t layer ); + +void pcb_route_calculate( pcb_route_t * p_route, + pcb_point_t * point1, + pcb_point_t * point2, + pcb_layer_id_t layer_id, + pcb_coord_t thickness, + pcb_coord_t clearance, + int mod1, + int mod2 ); +void pcb_route_direct( pcb_route_t * p_route, + pcb_point_t * point1, + pcb_point_t * point2, + pcb_layer_id_t layer, + pcb_coord_t thickness, + pcb_coord_t clearance ); + +void pcb_route_apply(const pcb_route_t * p_route); + +void pcb_route_draw( pcb_route_t * p_route,pcb_hid_gc_t GC ); +void pcb_route_draw_drc( pcb_route_t * p_route,pcb_hid_gc_t GC ); + +#endif /* ! defined GUARD_PCB_RND_ROUTE_H */