mirror of
git://projects.qi-hardware.com/cae-tools.git
synced 2024-12-23 04:23:55 +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:
parent
f6cf2e1b9b
commit
8999b3016a
@ -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
|
||||
|
@ -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,6 +109,9 @@ int main(int argc, char **argv)
|
||||
usage(*argv);
|
||||
}
|
||||
|
||||
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
93
cameo/gerber.c
Normal 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
22
cameo/gerber.h
Normal 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 */
|
||||
|
65
cameo/path.c
65
cameo/path.c
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user