1
0
mirror of git://projects.qi-hardware.com/cae-tools.git synced 2024-12-23 11:48:57 +02:00
cae-tools/cameo/path.c

279 lines
5.0 KiB
C
Raw Normal View History

/*
* path.c - Toolpath operations
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include "util.h"
#include "path.h"
struct path *path_new(double r_tool)
{
struct path *path;
path = alloc_type(struct path);
path->r_tool = r_tool;
path->first = path->last = NULL;
path->next = NULL;
return path;
}
static struct point *clone_point(struct point *p)
{
struct point *n;
n = alloc_type(struct point);
n->x = p->x;
n->y = p->y;
n->z = p->z;
n->next = NULL;
return n;
}
static int path_is_closed(const struct path *path)
{
if (path->first == path->last)
return 1;
return path->first->x == path->last->x &&
path->first->y == path->last->y && path->first->z == path->last->z;
}
static void path_add_point(struct path *path, struct point *p)
{
p->next = NULL;
if (path->last)
path->last->next = p;
else
path->first = p;
path->last = p;
}
void path_add(struct path *path, double x, double y, double z)
{
struct point *p;
p = alloc_type(struct point);
p->x = x;
p->y = y;
p->z = z;
return path_add_point(path, p);
}
struct path *path_reverse(const struct path *path)
{
struct path *new;
const struct point *p;
struct point *n;
new = path_new(path->r_tool);
for (p = path->first; p; p = p->next) {
n = alloc_type(struct point);
n->x = p->x;
n->y = p->y;
n->z = p->z;
n->next = new->first;
if (!new->last)
new->last = n;
new->first = n;
}
return new;
}
static struct point *offset_point(const struct point *a, const struct point *b,
const struct point *c, double off, int left)
{
double ax, ay, bx, by;
double aa, bb;
double nx, ny;
double angle, f;
struct point *p;
ax = b->x-a->x;
ay = b->y-a->y;
bx = c->x-b->x;
by = c->y-b->y;
aa = hypot(ax, ay);
bb = hypot(bx, by);
if (left) {
nx = -(ay/aa+by/bb);
ny = ax/aa+bx/bb;
} else {
nx = ay/aa+by/bb;
ny = -(ax/aa+bx/bb);
}
/* angle between AB and BC */
angle = acos(-(ax*bx+ay*by)/aa/bb);
/* multiplier for combination of normal vectors */
f = off/sin(angle/2);
f /= hypot(nx, ny);
nx *= f;
ny *= f;
p = alloc_type(struct point);
p->x = b->x+nx;
p->y = b->y+ny;
p->z = b->z;
p->next = NULL;
return p;
}
static int left_turn(const struct point *a, const struct point *b,
const struct point *c)
{
double ax, ay, bx, by;
ax = b->x-a->x;
ay = b->y-a->y;
bx = c->x-b->x;
by = c->y-b->y;
return (ax*by-ay*bx) >= 0;
}
/*
* Angle in counter-clockwise direction to turn at point B when coming from A
* in order to face towards C.
*/
static double angle_3(const struct point *a, const struct point *b,
const struct point *c)
{
double ax, ay, bx, by;
double aa, bb;
double angle;
ax = b->x-a->x;
ay = b->y-a->y;
bx = c->x-b->x;
by = c->y-b->y;
aa = hypot(ax, ay);
bb = hypot(bx, by);
angle = acos((ax*bx+ay*by)/aa/bb)/M_PI*180.0;
return (ax*by-ay*bx) >= 0 ? angle : -angle;
}
/*
* If we predominantly turn to the right, then the tool must be on the
* left-hand side. Otherwise, it's on the right.
*/
int path_tool_is_left(const struct path *path)
{
const struct point *prev, *p, *next;
double a = 0;
assert(path_is_closed(path));
prev = path->first;
for (p = path->first->next; p; p = p->next) {
next = p->next ? p->next : path->first->next;
a += angle_3(prev, p, next);
prev = p;
}
return a < 0;
}
/*
* http://www.makecnc.com/bones.jpg
*/
static struct point *dog_point(const struct point *edge,
const struct point *tool, double off)
{
double vx, vy, v;
struct point *p;
vx = edge->x-tool->x;
vy = edge->y-tool->y;
v = hypot(vx, vy);
vx *= 1-off/v;
vy *= 1-off/v;
p = alloc_type(struct point);
p->x = tool->x+vx;
p->y = tool->y+vy;
p->z = tool->z;
p->next = NULL;
return p;
}
/*
* The tool is on the "left" side of the path. E.g., if the path goes from
* 6 o'clock to 12 o'clock, the tool would be at 9 o'clock.
*/
struct path *path_offset(const struct path *path, int left, int notch)
{
struct path *new;
const struct point *prev, *p, *next;
struct point *n, *n2;
int dog;
assert(path_is_closed(path));
new = path_new(path->r_tool);
prev = path->first;
for (p = path->first->next; p; p = p->next) {
next = p->next ? p->next : path->first->next;
n = offset_point(prev, p, next, path->r_tool, left);
dog = notch && left_turn(prev, p, next) == left;
if (dog)
n2 = clone_point(n);
path_add_point(new, n);
if (dog) {
path_add_point(new, dog_point(p, n2, path->r_tool));
path_add_point(new, n2);
}
prev = p;
}
path_add_point(new, clone_point(new->first));
return new;
}
void path_free(struct path *path)
{
struct point *next;
while (path->first) {
next = path->first->next;
free(path->first);
path->first = next;
}
free(path);
}