r5613 - in developers/werner: . cncmap cncmap/millp cncmap/rect
werner at docs.openmoko.org
werner at docs.openmoko.org
Tue Sep 8 00:27:58 CEST 2009
Author: werner
Date: 2009-09-08 00:27:57 +0200 (Tue, 08 Sep 2009)
New Revision: 5613
Added:
developers/werner/cncmap/
developers/werner/cncmap/README
developers/werner/cncmap/millp/
developers/werner/cncmap/millp/Makefile
developers/werner/cncmap/millp/millp.c
developers/werner/cncmap/millp/serial.c
developers/werner/cncmap/millp/serial.h
developers/werner/cncmap/millp/usb.c
developers/werner/cncmap/millp/usb.h
developers/werner/cncmap/rect/
developers/werner/cncmap/rect/Makefile
developers/werner/cncmap/rect/lr.c
developers/werner/cncmap/rect/lr.h
developers/werner/cncmap/rect/rect.c
Log:
CNC tools for prototype development, first batch of them.
Added: developers/werner/cncmap/README
===================================================================
--- developers/werner/cncmap/README (rev 0)
+++ developers/werner/cncmap/README 2009-09-07 22:27:57 UTC (rev 5613)
@@ -0,0 +1,7 @@
+The "cncmap" package consists of the following tools:
+
+millp: interactively control a Roland MDX-15/20 mill, use a "millp" contact
+sensor for precise positioning, print the current coordinates.
+
+rect: find a rectangle defined by three corner points and print its corners
+in a normalized form.
Added: developers/werner/cncmap/millp/Makefile
===================================================================
--- developers/werner/cncmap/millp/Makefile (rev 0)
+++ developers/werner/cncmap/millp/Makefile 2009-09-07 22:27:57 UTC (rev 5613)
@@ -0,0 +1,25 @@
+#
+# millp/Makefile - Build the mill control utility
+#
+# Written 2008, 2009 by Werner Almesberger
+# Copyright 2008, 2009 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.
+#
+
+
+MAIN=millp
+
+OBJS=millp.o usb.o serial.o
+
+CFLAGS = -Wall -Wshadow
+LDFLAGS = -lusb
+
+$(MAIN): $(OBJS)
+# $(CC) $(LDFLAGS) -o $(MAIN) $(OBJS)
+
+clean:
+ rm -f $(OBJS)
Added: developers/werner/cncmap/millp/millp.c
===================================================================
--- developers/werner/cncmap/millp/millp.c (rev 0)
+++ developers/werner/cncmap/millp/millp.c 2009-09-07 22:27:57 UTC (rev 5613)
@@ -0,0 +1,368 @@
+/*
+ * millp.c - Manual mill control with contact sensing
+ *
+ * Written 2009 by Werner Almesberger
+ * Copyright 2009 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 <unistd.h>
+#include <sys/time.h>
+
+#include "serial.h"
+#include "usb.h"
+
+
+#define KEY_HOLD_MS 200 /* hold before continuous */
+#define KEY_STEP_MS 50 /* step when continuous */
+
+#define SEEK_STEP_MS 50 /* optimize coords for better res */
+
+#define MIN_X 0 /* 0 cm */
+#define MIN_Y 0 /* 0 cm */
+#define MIN_Z -60 /* 6 cm */
+
+#define MAX_X 150 /* 15 cm */
+#define MAX_Y 100 /* 10 cm */
+#define MAX_Z 0 /* 0 cm */
+
+
+static struct timeval t0; /* base time */
+static unsigned long ms; /* milliseconds since t0 */
+
+static char key = 0; /* current key, 0 if released */
+static unsigned long key_ms; /* milliseconds since last key change */
+static unsigned long key_t0_ms; /* time when the key was pressed/released */
+
+static int probe; /* probe results */
+
+static char dir; /* key of direction in which we seek */
+static unsigned long seek_last_ms;
+static int seek_coarse;
+
+
+static enum {
+ MODE_MANUAL,
+ MODE_SELECT,
+ MODE_SEEK,
+} mode = MODE_MANUAL;
+
+
+#define units(mm) ((mm)*40.0)
+
+
+static double x = 0, y = 0, z = 0;
+static int spindle = 0;
+
+
+static void move(void)
+{
+ serial_printf("!PZ%.1f,0;PD%.1f,%.1f\n", units(z), units(x), units(y));
+}
+
+
+static int rmove_3d(int dx, int dy, int dz, double s)
+{
+ int stop = 0;
+
+ x += dx*s;
+ y += dy*s;
+ z += dz*s;
+
+ if (x < MIN_X) {
+ x = MIN_X;
+ stop = 1;
+ }
+ if (y < MIN_Y) {
+ y = MIN_Y;
+ stop = 1;
+ }
+ if (z < MIN_Z) {
+ z = MIN_Z;
+ stop = 1;
+ }
+
+ if (x > MAX_X) {
+ x = MAX_X;
+ stop = 1;
+ }
+ if (y > MAX_Y) {
+ y = MAX_Y;
+ stop = 1;
+ }
+ if (z > MAX_Z) {
+ z = MAX_Z;
+ stop = 1;
+ }
+
+ move();
+
+ return stop;
+}
+
+
+static void update_time(void)
+{
+ struct timeval now;
+
+ (void) gettimeofday(&now, NULL);
+ now.tv_sec -= t0.tv_sec;
+ now.tv_usec -= t0.tv_usec;
+ ms = now.tv_sec*1000+now.tv_usec/1000;
+}
+
+
+static void do_cycle(int leds)
+{
+ int ch;
+
+ ch = cycle(leds, &probe);
+ if (ch != key) {
+ key = ch;
+ key_t0_ms = ms;
+ }
+ key_ms = ms-key_t0_ms;
+}
+
+
+static void reset_mode(void)
+{
+ mode = MODE_MANUAL;
+// key = 0;
+// key_ms = 0;
+}
+
+
+static int dir_key(char ch, int *dx, int *dy, int *dz)
+{
+ if (dx)
+ *dx = 0;
+ if (dy)
+ *dy = 0;
+ if (dz)
+ *dz = 0;
+
+ switch (ch) {
+ case 4:
+ if (dx)
+ *dx = -1;
+ return 1;
+ case 6:
+ if (dx)
+ *dx = 1;
+ return 1;
+ case 2:
+ if (dy)
+ *dy = -1;
+ return 1;
+ case 8:
+ if (dy)
+ *dy = 1;
+ return 1;
+ case 3:
+ if (dz)
+ *dz = -1;
+ return 1;
+ case 9:
+ if (dz)
+ *dz = 1;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
+static int mode_manual(void)
+{
+ static int once = 1;
+ int dx, dy, dz;
+
+ if (dir_key(key, &dx, &dy, &dz)) {
+ if (key_ms < KEY_HOLD_MS) {
+ if (once)
+ rmove_3d(dx, dy, dz, 0.1);
+ } else {
+ if (key_ms > KEY_HOLD_MS+KEY_STEP_MS) {
+ key_t0_ms += KEY_STEP_MS;
+ /* assume 10 mm/s, 50 ms */
+ rmove_3d(dx, dy, dz, 0.5);
+ }
+ }
+ once = 0;
+ return 0;
+ }
+ once = 1;
+
+ switch (key) {
+ case 5:
+ if (key_ms)
+ break;
+ spindle = !spindle;
+ serial_printf("!MC%d\n", spindle);
+ move();
+ break;
+ case 11:
+ mode = MODE_SELECT;
+ dir = 0;
+ break;
+ case 12:
+ return 1;
+ }
+ return 0;
+}
+
+
+static int mode_select(void)
+{
+ switch (key) {
+ case 0:
+ if (!dir)
+ break;
+ mode = MODE_SEEK;
+ seek_last_ms = ms;
+ seek_coarse = 1;
+ break;
+ case 11:
+ break;
+ case 1:
+ case 5:
+ case 7:
+ case 10:
+ case 12:
+ reset_mode();
+ break;
+ default:
+ if (dir_key(key, NULL, NULL, NULL))
+ dir = key;
+ break;
+ }
+ return 0;
+}
+
+
+static int mode_seek(int contact)
+{
+ int dx, dy, dz;
+
+ if (key) {
+ reset_mode();
+ return 0;
+ }
+
+ if (ms < seek_last_ms+SEEK_STEP_MS)
+ return 0;
+
+ seek_last_ms = ms;
+
+ (void) dir_key(dir, &dx, &dy, &dz);
+
+ if (seek_coarse) {
+ if (contact)
+ seek_coarse = 0;
+ else {
+ /* assume 2 mm/s, 50 ms */
+ if (rmove_3d(dx, dy, dz, 0.05))
+ mode = MODE_MANUAL;
+ }
+ } else {
+ if (contact) {
+ dx = -dx;
+ dy = -dy;
+ dz = -dz;
+ if (rmove_3d(dx, dy, dz, 0.01))
+ mode = MODE_MANUAL;
+ } else {
+ mode = MODE_MANUAL;
+ rmove_3d(dx, dy, dz, 0.01);
+ }
+ }
+ return 0;
+}
+
+
+int main(int argc, const char **argv)
+{
+ int show_once = 1;
+ int leds = 0;
+ int contact;
+
+ serial_open("/dev/ttyS0");
+ open_usb();
+ serial_printf("\nIN;!MC0\n");
+ move();
+ (void) gettimeofday(&t0, NULL);
+ while (1) {
+ int hz;
+
+ switch (mode) {
+ case MODE_MANUAL:
+ hz = 0;
+ break;
+ case MODE_SELECT:
+ hz = 1;
+ break;
+ case MODE_SEEK:
+ hz = 10;
+ break;
+ }
+ if (!hz || ((ms/(500/hz)) & 1))
+ leds |= LED_STATE;
+
+ update_time();
+ do_cycle(leds);
+
+ leds = 0;
+ contact = 0;
+ if (!(probe & PROBE_NORMAL)) {
+ leds = LED_CONTACT;
+ contact = 1;
+ if (key != 10)
+ key_ms = 0;
+ } else {
+ if (probe & PROBE_TEST_H)
+ leds |= LED_FAULT_H;
+ if (probe & PROBE_TEST_L)
+ leds |= LED_FAULT_L;
+ if (leds) {
+ key = 0;
+ reset_mode();
+ }
+ }
+
+ if (key == 10 && key_ms > 50 && show_once) {
+ do_cycle(leds & ~LED_STATE);
+ usleep(100000);
+ do_cycle(leds);
+ printf("%.2f %.2f %.2f\n", x, y, z);
+ show_once = 0;
+ }
+ if (!key)
+ show_once = 1;
+
+ switch (mode) {
+ case MODE_MANUAL:
+ if (mode_manual())
+ goto out;
+ break;
+ case MODE_SELECT:
+ if (mode_select())
+ goto out;
+ break;
+ case MODE_SEEK:
+ if (mode_seek(contact))
+ goto out;
+ break;
+ }
+ }
+out:
+ serial_close();
+ do_cycle(0);
+ return 0;
+}
Added: developers/werner/cncmap/millp/serial.c
===================================================================
--- developers/werner/cncmap/millp/serial.c (rev 0)
+++ developers/werner/cncmap/millp/serial.c 2009-09-07 22:27:57 UTC (rev 5613)
@@ -0,0 +1,100 @@
+/*
+ * serial.c - Send data to a Modela MDX-15/20
+ *
+ * Written 2009 by Werner Almesberger
+ * Copyright 2009 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 <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <sys/types.h>
+
+#include "serial.h"
+
+
+static int tty;
+static struct termios old;
+
+
+static void reset_tty(void)
+{
+ if (tty >= 0)
+ if (tcsetattr(tty, TCSADRAIN, &old) < 0)
+ perror("tcsetattr");
+}
+
+
+void serial_open(const char *name)
+{
+ struct termios new;
+
+
+ tty = open(name, O_WRONLY | O_NOCTTY);
+ if (tty < 0) {
+ perror(name);
+ exit(1);
+ }
+
+ if (tcgetattr(tty, &old) < 0) {
+ perror("tcgetattr");
+ exit(1);
+ }
+ atexit(reset_tty);
+
+ new = old;
+ cfmakeraw(&new);
+ cfsetospeed(&new, B9600);
+ new.c_iflag |= IXON;
+ new.c_cflag |= CLOCAL | CRTSCTS;
+ new.c_lflag &= ~ECHO;
+ if (tcsetattr(tty, TCSAFLUSH, &new) < 0) {
+ perror("tcsetattr");
+ exit(1);
+ }
+}
+
+
+void serial_close(void)
+{
+ reset_tty();
+ (void) close(tty);
+ tty = -1;
+}
+
+
+void serial_printf(const char *fmt, ...)
+{
+ char buf[10000]; /* more than enough :) */
+ va_list ap;
+ int len;
+ ssize_t wrote;
+
+ va_start(ap, fmt);
+ len = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ if (len >= sizeof(buf)-1) {
+ fprintf(stderr, "buffer too small\n");
+ exit(1);
+ }
+ wrote = write(tty, buf, strlen(buf));
+ if (wrote < 0) {
+ perror("write");
+ exit(1);
+ }
+ if (wrote != len) {
+ fprintf(stderr, "short write: %d < %d\n",
+ (int) wrote, (int) len);
+ exit(1);
+ }
+}
Added: developers/werner/cncmap/millp/serial.h
===================================================================
--- developers/werner/cncmap/millp/serial.h (rev 0)
+++ developers/werner/cncmap/millp/serial.h 2009-09-07 22:27:57 UTC (rev 5613)
@@ -0,0 +1,21 @@
+/*
+ * serial.h - Send data to a Modela MDX-15/20
+ *
+ * Written 2009 by Werner Almesberger
+ * Copyright 2009 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 SERIAL_H
+#define SERIAL_H
+
+void serial_open(const char *name);
+void serial_close(void);
+void serial_printf(const char *fmt, ...);
+
+#endif /* !SERIAL_H */
Added: developers/werner/cncmap/millp/usb.c
===================================================================
--- developers/werner/cncmap/millp/usb.c (rev 0)
+++ developers/werner/cncmap/millp/usb.c 2009-09-07 22:27:57 UTC (rev 5613)
@@ -0,0 +1,72 @@
+/*
+ * usb.c - Communicate to the millp control unit
+ *
+ * Written 2009 by Werner Almesberger
+ * Copyright 2009 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 <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <usb.h>
+
+#include "usb.h"
+
+
+#define TO_DEV 0x40
+#define FROM_DEV 0xc0
+
+
+static usb_dev_handle *dev_handle;
+
+
+void open_usb(void)
+{
+ const struct usb_bus *bus;
+ struct usb_device *dev;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ for (bus = usb_get_busses(); bus; bus = bus->next)
+ for (dev = bus->devices; dev; dev = dev->next) {
+ if (dev->descriptor.idVendor != VENDOR_ID)
+ continue;
+ if (dev->descriptor.idProduct != PRODUCT_ID)
+ continue;
+ dev_handle = usb_open(dev);
+ if (dev_handle)
+ return;
+ fprintf(stderr, "can't open device\n");
+ exit(1);
+ }
+ fprintf(stderr, "no device found\n");
+ exit(1);
+}
+
+
+char cycle(int leds, int *probe)
+{
+ uint8_t data[2];
+ int res;
+
+ res = usb_control_msg(dev_handle, FROM_DEV, MILLP_CYCLE, leds, 0,
+ (void *) data, 2, 1000);
+ if (res < 0) {
+ fprintf(stderr, "MILLP_CYCLE: %d\n", res);
+ exit(1);
+ }
+ if (res != 2) {
+ fprintf(stderr, "MILLP_CYCLE: expected 2 bytes, got %d\n", res);
+ exit(1);
+ }
+
+ *probe = data[1];
+ return *data;
+}
Added: developers/werner/cncmap/millp/usb.h
===================================================================
--- developers/werner/cncmap/millp/usb.h (rev 0)
+++ developers/werner/cncmap/millp/usb.h 2009-09-07 22:27:57 UTC (rev 5613)
@@ -0,0 +1,33 @@
+/*
+ * usb.h - Communicate to the millp control unit
+ *
+ * Written 2009 by Werner Almesberger
+ * Copyright 2009 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 USB_H
+#define USB_H
+
+#define VENDOR_ID 0x1d50 /* borrow from IDBG */
+#define PRODUCT_ID 0x1db6 /* borrow from IDBG */
+
+#define MILLP_CYCLE 0x10 /* we don't need the other commands */
+
+#define LED_FAULT_H 1
+#define LED_FAULT_L 2
+#define LED_CONTACT 4
+#define LED_STATE 8
+
+#define PROBE_NORMAL 1
+#define PROBE_TEST_L 2
+#define PROBE_TEST_H 4
+
+void open_usb(void);
+char cycle(int leds, int *probe);
+
+#endif /* !USB_H */
Added: developers/werner/cncmap/rect/Makefile
===================================================================
--- developers/werner/cncmap/rect/Makefile (rev 0)
+++ developers/werner/cncmap/rect/Makefile 2009-09-07 22:27:57 UTC (rev 5613)
@@ -0,0 +1,25 @@
+#
+# millp/Makefile - Build the mill control utility
+#
+# Written 2008, 2009 by Werner Almesberger
+# Copyright 2008, 2009 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.
+#
+
+
+MAIN=rect
+
+OBJS=rect.o lr.o
+
+CFLAGS = -Wall -Wshadow
+LDFLAGS = -lm
+
+$(MAIN): $(OBJS)
+# $(CC) $(LDFLAGS) -o $(MAIN) $(OBJS)
+
+clean:
+ rm -f $(OBJS)
Added: developers/werner/cncmap/rect/lr.c
===================================================================
--- developers/werner/cncmap/rect/lr.c (rev 0)
+++ developers/werner/cncmap/rect/lr.c 2009-09-07 22:27:57 UTC (rev 5613)
@@ -0,0 +1,100 @@
+/*
+ * lr.c - Least square approximation of plane
+ *
+ * Written 2009 by Werner Almesberger
+ * Copyright 2009 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.
+ */
+
+/*
+ * http://en.wikipedia.org/wiki/Linear_least_squares
+ * http://en.wikipedia.org/wiki/Linear_regression#Example
+ * http://en.wikipedia.org/wiki/Cramer's_rule
+ * http://en.wikipedia.org/wiki/Determinant
+ */
+
+
+#include "lr.h"
+
+
+#define MAX_N 1000
+
+
+static double x[MAX_N][3], y[MAX_N];
+static int n = 0;
+
+
+static double det3(double m[3][3])
+{
+ double s = 0;
+ double p;
+ int i, j;
+
+ for (i = 0; i != 3; i++) {
+ p = 1;
+ for (j = 0; j != 3; j++)
+ p *= m[j][(i+j) % 3];
+ s += p;
+ p = 1;
+ for (j = 0; j != 3; j++)
+ p *= m[2-j][(i+j) % 3];
+ s -= p;
+ }
+ return s;
+}
+
+
+static void cramer3(double r[3], double m[3][3], double v[3])
+{
+ double t[3][3];
+ double d;
+ int i, j, k;
+
+ d = det3(m);
+ for (i = 0; i != 3; i++) {
+ for (j = 0; j != 3; j++)
+ for (k = 0; k != 3; k++)
+ t[j][k] = m[j][k];
+ for (j = 0; j != 3; j++)
+ t[j][i] = v[j];
+ r[i] = det3(t)/d;
+ }
+}
+
+
+void lr_point(double px, double py, double pz)
+{
+ x[n][0] = 1;
+ x[n][1] = px;
+ x[n][2] = py;
+ y[n] = pz;
+ n++;
+}
+
+
+void lr_calc(double *z0, double *zx, double *zy)
+{
+ double m[3][3], v[3];
+ double r[3];
+ int i, j, k;
+
+ for (i = 0; i != 3; i++)
+ for (j = 0; j != 3; j++) {
+ m[i][j] = 0;
+ for (k = 0; k != n; k++)
+ m[i][j] += x[k][i]*x[k][j];
+ }
+ for (i = 0; i != 3; i++) {
+ v[i] = 0;
+ for (k = 0; k != n; k++)
+ v[i] += x[k][i]*y[k];
+ }
+ cramer3(r, m, v);
+ *z0 = r[0];
+ *zx = r[1];
+ *zy = r[2];
+}
Added: developers/werner/cncmap/rect/lr.h
===================================================================
--- developers/werner/cncmap/rect/lr.h (rev 0)
+++ developers/werner/cncmap/rect/lr.h 2009-09-07 22:27:57 UTC (rev 5613)
@@ -0,0 +1,20 @@
+/*
+ * lr.h - Least square approximation of plane
+ *
+ * Written 2009 by Werner Almesberger
+ * Copyright 2009 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 LR_H
+#define LR_H
+
+void lr_point(double x, double y, double z);
+void lr_calc(double *z0, double *zx, double *zy);
+
+#endif /* !LR_H */
Added: developers/werner/cncmap/rect/rect.c
===================================================================
--- developers/werner/cncmap/rect/rect.c (rev 0)
+++ developers/werner/cncmap/rect/rect.c 2009-09-07 22:27:57 UTC (rev 5613)
@@ -0,0 +1,149 @@
+/*
+ * rect.c - Find the rectangle described by three corner points
+ *
+ * Written 2009 by Werner Almesberger
+ * Copyright 2009 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 <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "lr.h"
+
+
+#define FUZZ 10 /* rectangularity tolerance, in degrees */
+
+
+static double p[9];
+static int o, a, b; /* offset into "p" of origin, side A, side B */
+static double ox, oy, oz, ax, ay, az, bx, by, bz;
+static double a_len, b_len;
+static double rot; /* angle of A with respect to the x axis */
+static double angle; /* angle from A to B in a counter-clockwise direction */
+static double z0, zx, zy;
+
+
+static void usage(const char *name)
+{
+ fprintf(stderr, "usage: %s x0 y0 z0 ax ay az bx by bz\n", name);
+ exit(1);
+}
+
+
+static void calculate(void)
+{
+ ox = p[o];
+ oy = p[o+1];
+ oz = p[o+2];
+ ax = p[a]-ox;
+ ay = p[a+1]-oy;
+ az = p[a+2]-oz;
+ bx = p[b]-ox;
+ by = p[b+1]-oy;
+ bz = p[b+2]-oz;
+
+ a_len = hypot(ax, ay);
+ rot = atan2(ay, ax);
+ b_len = hypot(bx, by);
+ angle = atan2(by, bx)-rot;
+
+ if (angle < 0)
+ angle += M_PI*2;
+}
+
+
+static double z(double x, double y)
+{
+ return z0+x*zx+y*zy;
+}
+
+
+int main(int argc, char **argv)
+{
+ int i;
+ char *end;
+ double best_angle;
+ int best_o, best_a, best_b;
+ double diff;
+
+ if (argc != 10)
+ usage(*argv);
+ for (i = 0; i != 9; i++) {
+ p[i] = strtod(argv[i+1], &end);
+ if (*end)
+ usage(*argv);
+ }
+
+ for (i = 0; i != 9; i += 3)
+ lr_point(p[i], p[i+1], p[i+2]);
+ lr_calc(&z0, &zx, &zy);
+
+ best_angle = 0;
+ for (o = 0; o != 9; o += 3) {
+ for (a = 0; a != 9; a += 3) {
+ if (a == o)
+ continue;
+ for (b = 0; b != 9; b += 3) {
+ if (b == o || b == a)
+ continue;
+ calculate();
+fprintf(stderr, "%d %d %d -> %f\n", o, a, b, angle/M_PI*180);
+ diff = fabs(angle-M_PI/2);
+ if (diff > fabs(best_angle-M_PI/2))
+ continue;
+ if (diff > FUZZ*M_PI/180)
+ continue;
+ best_angle = angle;
+ best_o = o;
+ best_a = a;
+ best_b = b;
+ }
+ }
+ }
+
+ if (!best_angle) {
+ fprintf(stderr, "no suitable fit found\n");
+ return 1;
+ }
+
+ o = best_o;
+ a = best_a;
+ b = best_b;
+
+ calculate();
+
+ fprintf(stderr, "A = %f, rot %f\n", a_len, rot/M_PI*180);
+ fprintf(stderr, "B = %f, angle %f\n", b_len, angle/M_PI*180);
+ fprintf(stderr, "phi: x %f (%f%%), y %f (%f%%)\n",
+ atan(zx)/M_PI*180, zx*100, atan(zy)/M_PI*180, zy*100);
+
+ /*
+ * Use the angle of the longer side, since it's probably more accurate.
+ */
+ if (a_len > b_len) {
+ angle = rot+M_PI/2;
+ bx = b_len*cos(angle);
+ by = b_len*sin(angle);
+ } else {
+ angle = rot+angle-M_PI/2;
+ ax = a_len*cos(angle);
+ ay = a_len*sin(angle);
+ }
+
+ ax += ox;
+ ay += oy;
+ bx += ox;
+ by += oy;
+
+ printf("%.2f %.2f %.2f\n", ox, oy, z(ox, oy));
+ printf("%.2f %.2f %.2f\n", ax, ay, z(ax, ay));
+ printf("%.2f %.2f %.2f\n", bx, by, z(bx, by));
+
+ return 0;
+}
More information about the commitlog
mailing list