Code: Select all
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include <float.h>
struct touchpoint
{
double x, y;
};
static int find_touchpoints (struct touchpoint *pts, char pic[15][30])
{
int xbuf[15 * 30];
int ybuf[15 * 30];
int n = 0;
for (int x = 0; x < 30; x++)
for (int y = 0; y < 15; y++)
{
if (pic[y][x] != 'X')
continue;
int xtotal = 0;
int ytotal = 0;
xbuf[0] = x;
ybuf[0] = y;
pic[y][x] = '0' + n;
int nwork = 1;
for (int i = 0; i < nwork; i++)
{
int xt = xbuf[i];
int yt = ybuf[i];
xtotal += xt;
ytotal += yt;
if (xt > 0 && pic[yt][xt - 1] == 'X')
{
xbuf[nwork] = xt - 1;
ybuf[nwork] = yt;
nwork++;
pic[yt][xt - 1] = '0' + n;
}
if (xt + 1 < 30 && pic[yt][xt + 1] == 'X')
{
xbuf[nwork] = xt + 1;
ybuf[nwork] = yt;
nwork++;
pic[yt][xt + 1] = '0' + n;
}
if (yt > 0 && pic[yt - 1][xt] == 'X')
{
xbuf[nwork] = xt;
ybuf[nwork] = yt - 1;
nwork++;
pic[yt - 1][xt] = '0' + n;
}
if (yt + 1 < 15 && pic[yt + 1][xt] == 'X')
{
xbuf[nwork] = xt;
ybuf[nwork] = yt + 1;
nwork++;
pic[yt + 1][xt] = '0' + n;
}
}
pts[n].x = (double)xtotal / nwork;
pts[n].y = (double)ytotal / nwork;
n++;
}
return n;
}
static void print_pic (char pic[15][30])
{
for (int y = 0; y < 15; y++)
{
for (int x = 0; x < 30; x++)
putchar (pic[y][x]);
putchar ('\n');
}
}
static double match (struct touchpoint *pts_a, struct touchpoint *pts_b,
int *matches, int *best_matches, int *used, double best, double sum, int n, int len)
{
if (n == len)
{
if (sum < best)
memcpy (best_matches, matches, 5 * sizeof (int));
return sum;
}
for (int i = 0; i < len; i++)
if (!used[i])
{
used[i] = 1;
matches[n] = i;
double xd = (pts_a[n].x - pts_b[i].x);
double yd = (pts_a[n].y - pts_b[i].y);
double t_sum = sum + xd * xd + yd * yd;
double t = match (pts_a, pts_b, matches, best_matches, used, best, t_sum, n + 1, len);
if (t < best)
best = t;
used[i] = 0;
}
return best;
}
int main (int argc, char **argv)
{
char *line = NULL;
size_t llen = 0;
char pic_a[15][30];
char pic_b[15][30];
struct touchpoint pts_a[5], pts_b[5];
for (int i = 0; i < 15; i++)
{
if (getline (&line, &llen, stdin) < 0)
abort ();
memcpy (pic_a[i], line, 30);
memcpy (pic_b[i], line + 31, 30);
}
int npt_a = find_touchpoints (pts_a, pic_a);
int npt_b = find_touchpoints (pts_b, pic_b);
if (npt_a != npt_b)
abort ();
#ifdef DEBUG
print_pic (pic_a);
putchar ('\n');
print_pic (pic_b);
#endif
int best_matches[5];
int matches[5];
int used[5];
memset (used, 0, sizeof (used));
double best = match (pts_a, pts_b, matches, best_matches, used, DBL_MAX, 0, 0, npt_a);
#ifdef DEBUG
printf ("%f\n", best);
for (int i = 0; i < npt_a; i++)
{
int n = best_matches[i];
printf ("[%d] %f:%f [%d] %f:%f\n", i, pts_a[i].x, pts_a[i].y, n, pts_b[n].x, pts_b[n].y);
}
#endif
double grip_xa = 0;
double grip_xb = 0;
double grip_ya = 0;
double grip_yb = 0;
for (int i = 0; i < npt_b; i++)
{
grip_xa += pts_a[i].x;
grip_xb += pts_b[i].x;
grip_ya += pts_a[i].y;
grip_yb += pts_b[i].y;
}
grip_xa /= npt_a;
grip_xb /= npt_b;
grip_ya /= npt_a;
grip_yb /= npt_b;
double grip_xd = grip_xa - grip_xb;
double grip_yd = grip_ya - grip_yb;
double grip_dist = sqrt (grip_xd * grip_xd + grip_yd * grip_yd);
#ifdef DEBUG
printf ("grips: %f:%f %f:%f dist %f\n", grip_xa, grip_ya, grip_xb, grip_yb, grip_dist);
#endif
double spread_a = 0;
double spread_b = 0;
for (int i = 0; i < npt_b; i++)
{
double axd = pts_a[i].x - grip_xa;
double ayd = pts_a[i].y - grip_ya;
double bxd = pts_b[i].x - grip_xb;
double byd = pts_b[i].y - grip_yb;
spread_a += sqrt (axd * axd + ayd * ayd);
spread_b += sqrt (bxd * bxd + byd * byd);
}
spread_a /= npt_a;
spread_b /= npt_b;
double avg_angle = 0;
for (int i = 0; i < npt_a; i++)
{
int n = best_matches[i];
double vecxa = pts_a[i].x - grip_xa;
double vecya = pts_a[i].y - grip_ya;
double vecxb = pts_b[n].x - grip_xb;
double vecyb = pts_b[n].y - grip_yb;
double lena = sqrt (vecxa * vecxa + vecya * vecya);
double lenb = sqrt (vecxb * vecxb + vecyb * vecyb);
double angle = atan2 (vecyb, vecxb) - atan2 (vecya, vecxa);
if (angle > M_PI)
angle -= 2 * M_PI;
else if (angle < -M_PI)
angle += 2 * M_PI;
avg_angle += angle;
#ifdef DEBUG
printf ("%d [%f %f -> %f]\n", n, lena, lenb, angle);
#endif
}
avg_angle /= npt_a;
double rot_dist = avg_angle * spread_a;
#ifdef DEBUG
printf ("angle %f, spread %f, rot_dist %f\n", avg_angle, spread_a, rot_dist);
#endif
printf ("%d ", npt_a);
if (fabs (rot_dist) > fabs (spread_a - spread_b) && fabs (rot_dist) > grip_dist)
{
printf ("rotate ");
if (rot_dist < 0)
printf ("counter-");
puts ("clockwise");
}
else if (fabs (spread_a - spread_b) > grip_dist)
{
if (spread_a > spread_b)
puts ("zoom in");
else
puts ("zoom out");
}
else
printf ("pan\n");
exit (0);
}