mirror of
git://projects.qi-hardware.com/cae-tools.git
synced 2025-01-09 01:30:14 +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
|
SHELL=/bin/bash
|
||||||
|
|
||||||
MAIN=cameo
|
MAIN=cameo
|
||||||
OBJS=cameo.o gnuplot.o path.o
|
OBJS=cameo.o gerber.o gnuplot.o path.o
|
||||||
|
|
||||||
CFLAGS_WARN=-Wall -Wshadow -Wmissing-prototypes \
|
CFLAGS_WARN=-Wall -Wshadow -Wmissing-prototypes \
|
||||||
-Wmissing-declarations -Wno-format-zero-length
|
-Wmissing-declarations -Wno-format-zero-length
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "gnuplot.h"
|
#include "gnuplot.h"
|
||||||
|
#include "gerber.h"
|
||||||
|
|
||||||
|
|
||||||
static int dog_bone = 0;
|
static int dog_bone = 0;
|
||||||
@ -65,9 +66,11 @@ static void process_paths(struct path *paths)
|
|||||||
static void usage(const char *name)
|
static void usage(const char *name)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
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"
|
" -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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,15 +78,19 @@ static void usage(const char *name)
|
|||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char *in = NULL, *out = NULL;
|
char *in = NULL, *out = NULL;
|
||||||
|
int gerber = 0;
|
||||||
double r;
|
double r;
|
||||||
struct path *paths;
|
struct path *paths;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "d")) != EOF)
|
while ((c = getopt(argc, argv, "dg")) != EOF)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'd':
|
case 'd':
|
||||||
dog_bone = 1;
|
dog_bone = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'g':
|
||||||
|
gerber = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage(*argv);
|
usage(*argv);
|
||||||
}
|
}
|
||||||
@ -102,7 +109,10 @@ int main(int argc, char **argv)
|
|||||||
usage(*argv);
|
usage(*argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
paths = gnuplot_read(in, r);
|
if (gerber)
|
||||||
|
paths = gerber_read(in, r);
|
||||||
|
else
|
||||||
|
paths = gnuplot_read(in, r);
|
||||||
process_paths(paths);
|
process_paths(paths);
|
||||||
gnuplot_write(out, 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,
|
static struct point *offset_point(const struct point *a, const struct point *b,
|
||||||
const struct point *c, double off, int left)
|
const struct point *c, double off, int left)
|
||||||
{
|
{
|
||||||
@ -331,3 +345,54 @@ struct path *path_find_leftmost(struct path *path)
|
|||||||
}
|
}
|
||||||
return best;
|
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_offset(const struct path *path, int left, int notch);
|
||||||
struct path *path_find_leftmost(struct path *path);
|
struct path *path_find_leftmost(struct path *path);
|
||||||
void path_free(struct path *path);
|
void path_free(struct path *path);
|
||||||
|
struct path *path_connect(struct path *path);
|
||||||
|
|
||||||
#endif /* !PATH_H */
|
#endif /* !PATH_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user