1
0
mirror of git://projects.qi-hardware.com/cae-tools.git synced 2024-12-22 23:59:34 +02:00

cameo: added KiCad Gerber input and path merging

- Makefile (OBJS): added gerber.o
- cameo.c (usage, main): new option -g to process input a KiCad Gerber
- gerber.h, gerber.c (gerber_read): parse Gerber files as generated by KiCad
- path.h, path.c (path_reverse_inplace, points_eq, attr_eq, path_connect):
  merge sets of paths with equal endpoints into single paths
This commit is contained in:
Werner Almesberger 2010-12-13 17:45:33 -03:00
parent f6cf2e1b9b
commit 8999b3016a
6 changed files with 196 additions and 5 deletions

View File

@ -15,7 +15,7 @@ PREFIX ?= /usr/local
SHELL=/bin/bash
MAIN=cameo
OBJS=cameo.o gnuplot.o path.o
OBJS=cameo.o gerber.o gnuplot.o path.o
CFLAGS_WARN=-Wall -Wshadow -Wmissing-prototypes \
-Wmissing-declarations -Wno-format-zero-length

View File

@ -17,6 +17,7 @@
#include "path.h"
#include "gnuplot.h"
#include "gerber.h"
static int dog_bone = 0;
@ -65,9 +66,11 @@ static void process_paths(struct path *paths)
static void usage(const char *name)
{
fprintf(stderr,
"usage: %s [-d] r_mm [in.gnuplot [out.gnuplot]]\n\n"
"usage: %s [-d] r_mm [in.gnuplot [out.gnuplot]]\n"
" %s -g [-d] r_mm [in.gerber [out.gnuplot]]\n\n"
" -d put a dog-bone notch in each concave external corner\n"
, name);
" -g input format is KiCad Gerber, not gnuplot\n"
, name, name);
exit(1);
}
@ -75,15 +78,19 @@ static void usage(const char *name)
int main(int argc, char **argv)
{
char *in = NULL, *out = NULL;
int gerber = 0;
double r;
struct path *paths;
int c;
while ((c = getopt(argc, argv, "d")) != EOF)
while ((c = getopt(argc, argv, "dg")) != EOF)
switch (c) {
case 'd':
dog_bone = 1;
break;
case 'g':
gerber = 1;
break;
default:
usage(*argv);
}
@ -102,7 +109,10 @@ int main(int argc, char **argv)
usage(*argv);
}
paths = gnuplot_read(in, r);
if (gerber)
paths = gerber_read(in, r);
else
paths = gnuplot_read(in, r);
process_paths(paths);
gnuplot_write(out, paths);

93
cameo/gerber.c Normal file
View File

@ -0,0 +1,93 @@
/*
* gerber.c - Gerber file input
*
* Written 2010 by Werner Almesberger
* Copyright 2010 Werner Almesberger
*
* 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.
*/
/*
* Note: this is limited to the Gerber produced by KiCad for the PCB Edge
* layer. Furthermore, we ignore the tool diameter for now.
*
* The relevant details are nicely explained at
* http://www.pcbmilling.com/Examples of Gerber and Excellon Data Files.htm
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "path.h"
#include "gerber.h"
/* KiCad Gerber uses 0.1 mil units */
#define KU2MM(in) ((in)/10000.0*25.4)
struct path *gerber_read(const char *name, double r_tool_default)
{
FILE *file;
int lineno = 0;
char buf[1024];
struct path *paths = NULL, **anchor = &paths, *path = NULL;
int start_x = 0, start_y = 0;
int x, y, d;
file = name ? fopen(name, "r") : stdin;
if (!file) {
perror(name);
exit(1);
}
while (fgets(buf, sizeof(buf), file)) {
lineno++;
if (!strncmp(buf, "%FS", 3)) {
if (strcmp(buf, "%FSLAX34Y34*%\n")) {
fprintf(stderr,
"unrecognized format %s\n", buf);
exit(1);
}
continue;
}
if (!strncmp(buf, "%MO", 3)) {
if (strcmp(buf, "%MOIN*%\n")) {
fprintf(stderr,
"unrecognized mode %s\n", buf);
exit(1);
}
continue;
}
if (sscanf(buf, "X%dY%dD%d*\n", &x, &y, &d) != 3)
continue;
x = KU2MM(x);
y = KU2MM(y);
switch (d) {
case 1:
if (!path) {
path = path_new(r_tool_default);
*anchor = path;
anchor = &path->next;
path_add(path, start_x, start_y, 0);
}
path_add(path, x, y, 0);
break;
case 2:
path = NULL;
start_x = x;
start_y = y;
break;
default:
fprintf(stderr, "don't recognize D%d\n", d);
exit(1);
}
}
fclose(file);
return path_connect(paths);
}

22
cameo/gerber.h Normal file
View File

@ -0,0 +1,22 @@
/*
* gerber.h - Gerber file input
*
* Written 2010 by Werner Almesberger
* Copyright 2010 Werner Almesberger
*
* 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.
*/
#ifndef GERBER_H
#define GERBER_H
#include "path.h"
struct path *gerber_read(const char *name, double r_tool_default);
#endif /* !GERBER_H */

View File

@ -147,6 +147,20 @@ struct path *path_reverse(const struct path *path)
}
static void path_reverse_inplace(struct path *path)
{
struct point *points = NULL, *p, *next;
path->last = path->first;
for (p = path->first; p; p = next) {
next = p->next;
p->next = points;
points = p;
}
path->first = points;
}
static struct point *offset_point(const struct point *a, const struct point *b,
const struct point *c, double off, int left)
{
@ -331,3 +345,54 @@ struct path *path_find_leftmost(struct path *path)
}
return best;
}
static int points_eq(const struct point *a, const struct point *b)
{
return a->x == b->x && a->y == b->y && a->z == b->z;
}
static int attr_eq(const struct path *a, const struct path *b)
{
return a->r_tool == b->r_tool && a->outside == b->outside &&
a->notch == b->notch;
}
struct path *path_connect(struct path *path)
{
struct path **a, **b;
struct path *tmp;
again:
for (a = &path; *a; a = &(*a)->next)
for (b = &(*a)->next; *b; b = &(*b)->next) {
if (!attr_eq(*a, *b))
continue;
if (points_eq((*a)->last, (*b)->last))
path_reverse_inplace(*b);
if (points_eq((*a)->last, (*b)->first)) {
(*a)->last->next = (*b)->first->next;
(*a)->last = (*b)->last;
free((*b)->first);
tmp = *b;
*b = tmp->next;
free(tmp);
goto again;
}
if (points_eq((*a)->first, (*b)->first))
path_reverse_inplace(*b);
if (points_eq((*a)->first, (*b)->last)) {
(*b)->last->next = (*a)->first->next;
(*b)->last = (*a)->last;
free((*a)->first);
tmp = *a;
*a = *b;
free(tmp);
*b = (*b)->next;
goto again;
}
}
return path;
}

View File

@ -37,5 +37,6 @@ int path_tool_is_left(const struct path *path);
struct path *path_offset(const struct path *path, int left, int notch);
struct path *path_find_leftmost(struct path *path);
void path_free(struct path *path);
struct path *path_connect(struct path *path);
#endif /* !PATH_H */