gimp/app/tools/airbrush_blob.c

1798 lines
48 KiB
C

/* airbrush_blob.c: routines for manipulating scan converted convex
* polygons.
*
* Copyright 1998-1999, Owen Taylor <otaylor@gtk.org>
*
* > Please contact the above author before modifying the copy <
* > of this file in the GIMP distribution. Thanks. <
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "airbrush_blob.h"
#include <glib.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROUND(A) floor((A)+0.5)
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif /* M_PI */
#ifndef M_PI_H
#define M_PI_H 3.14159265358979323846/2
#endif
#define SUBSAMPLE 8.0
static AirBrushBlob *
airbrush_blob_new (int y, int height)
{
AirBrushBlob *result;
result = g_malloc (sizeof (AirBrushBlob) + sizeof(AirBrushBlobSpan) * (height-1));
result->y = y;
result->height = height;
return result;
}
static AirBlob *
airblob_new(int y)
{
AirBlob *result;
result = g_malloc (sizeof (AirBlob));
return result;
}
static AirLine *
airline_new(int y)
{
AirLine *result;
result = g_malloc(sizeof (AirLine));
return result;
}
typedef enum {
EDGE_NONE = 0,
EDGE_LEFT = 1 << 0,
EDGE_RIGHT = 1 << 1
} EdgeType;
static void
airbrush_blob_fill (AirBrushBlob *b, EdgeType *present)
{
int start;
int x1, x2, i1, i2;
int i;
/* Mark empty lines at top and bottom as unused */
start = 0;
while (!(present[start]))
{
b->data[start].left = 0;
b->data[start].right = -1;
start++;
}
if (present[start] != (EDGE_RIGHT | EDGE_LEFT))
{
if (present[start] == EDGE_RIGHT)
b->data[start].left = b->data[start].right;
else
b->data[start].right = b->data[start].left;
present[start] = EDGE_RIGHT | EDGE_LEFT;
}
for (i=b->height-1;!present[i];i--)
{
b->data[i].left = 0;
b->data[i].right = -1;
}
if (present[i] != (EDGE_RIGHT | EDGE_LEFT))
{
if (present[i] == EDGE_RIGHT)
b->data[i].left = b->data[i].right;
else
b->data[i].right = b->data[i].left;
present[i] = EDGE_RIGHT | EDGE_LEFT;
}
/* Restore missing edges */
/* We fill only interior regions of convex hull, as if we were filling
polygons. But since we draw ellipses with nearest points, not interior
points, maybe it would look better if we did the same here. Probably
not a big deal either way after anti-aliasing */
/* left edge */
for (i1=start; i1<b->height-2; i1++)
{
/* Find empty gaps */
if (!(present[i1+1] & EDGE_LEFT))
{
int increment; /* fractional part */
int denom; /* denominator of fraction */
int step; /* integral step */
int frac; /* fractional step */
int reverse;
/* find bottom of gap */
i2 = i1+2;
while (!(present[i2] & EDGE_LEFT) && i2 < b->height) i2++;
if (i2 < b->height)
{
denom = i2-i1;
x1 = b->data[i1].left;
x2 = b->data[i2].left;
step = (x2-x1)/denom;
frac = x2-x1 - step*denom;
if (frac < 0)
{
frac = -frac;
reverse = 1;
}
else
reverse = 0;
increment = 0;
for (i=i1+1; i<i2; i++)
{
x1 += step;
increment += frac;
if (increment >= denom)
{
increment -= denom;
x1 += reverse ? -1 : 1;
}
if (increment == 0 || reverse)
b->data[i].left = x1;
else
b->data[i].left = x1 + 1;
}
}
i1 = i2-1; /* advance to next possibility */
}
}
/* right edge */
for (i1=start; i1<b->height-2; i1++)
{
/* Find empty gaps */
if (!(present[i1+1] & EDGE_RIGHT))
{
int increment; /* fractional part */
int denom; /* denominator of fraction */
int step; /* integral step */
int frac; /* fractional step */
int reverse;
/* find bottom of gap */
i2 = i1+2;
while (!(present[i2] & EDGE_RIGHT) && i2 < b->height) i2++;
if (i2 < b->height)
{
denom = i2-i1;
x1 = b->data[i1].right;
x2 = b->data[i2].right;
step = (x2-x1)/denom;
frac = x2-x1 - step*denom;
if (frac < 0)
{
frac = -frac;
reverse = 1;
}
else
reverse = 0;
increment = 0;
for (i=i1+1; i<i2; i++)
{
x1 += step;
increment += frac;
if (increment >= denom)
{
increment -= denom;
x1 += reverse ? -1 : 1;
}
if (reverse && increment != 0)
b->data[i].right = x1 - 1;
else
b->data[i].right = x1;
}
}
i1 = i2-1; /* advance to next possibility */
}
}
}
static void
airbrush_blob_make_convex (AirBrushBlob *b, EdgeType *present)
{
int x1, x2, y1, y2, i1, i2;
int i;
int start;
/* Walk through edges, deleting points that aren't on convex hull */
start = 0;
while (!(present[start])) start++;
/* left edge */
i1 = start-1;
i2 = start;
x1 = b->data[start].left - b->data[start].right;
y1 = 0;
for (i=start+1;i<b->height;i++)
{
if (!(present[i] & EDGE_LEFT))
continue;
x2 = b->data[i].left - b->data[i2].left;
y2 = i-i2;
while (x2*y1 - x1*y2 < 0) /* clockwise rotation */
{
present[i2] &= ~EDGE_LEFT;
i2 = i1;
while (!(present[--i1] & EDGE_LEFT) && i1>=start);
if (i1<start)
{
x1 = b->data[start].left - b->data[start].right;
y1 = 0;
}
else
{
x1 = b->data[i2].left - b->data[i1].left;
y1 = i2 - i1;
}
x2 = b->data[i].left - b->data[i2].left;
y2 = i - i2;
}
x1 = x2;
y1 = y2;
i1 = i2;
i2 = i;
}
/* Right edge */
i1 = start -1;
i2 = start;
x1 = b->data[start].right - b->data[start].left;
y1 = 0;
for (i=start+1;i<b->height;i++)
{
if (!(present[i] & EDGE_RIGHT))
continue;
x2 = b->data[i].right - b->data[i2].right;
y2 = i-i2;
while (x2*y1 - x1*y2 > 0) /* counter-clockwise rotation */
{
present[i2] &= ~EDGE_RIGHT;
i2 = i1;
while (!(present[--i1] & EDGE_RIGHT) && i1>=start);
if (i1<start)
{
x1 = b->data[start].right - b->data[start].left;
y1 = 0;
}
else
{
x1 = b->data[i2].right - b->data[i1].right;
y1 = i2 - i1;
}
x2 = b->data[i].right - b->data[i2].right;
y2 = i - i2;
}
x1 = x2;
y1 = y2;
i1 = i2;
i2 = i;
}
airbrush_blob_fill (b, present);
}
AirBrushBlob *
airbrush_blob_convex_union (AirBrushBlob *b1, AirBrushBlob *b2)
{
AirBrushBlob *result;
int y;
int i, j;
EdgeType *present;
/* Create the storage for the result */
y = MIN(b1->y,b2->y);
result = airbrush_blob_new (y, MAX(b1->y+b1->height,b2->y+b2->height)-y);
if (result->height == 0)
return result;
present = g_new0 (EdgeType, result->height);
/* Initialize spans from original objects */
for (i=0, j=b1->y-y; i<b1->height; i++,j++)
{
if (b1->data[i].right >= b1->data[i].left)
{
present[j] = EDGE_LEFT | EDGE_RIGHT;
result->data[j].left = b1->data[i].left;
result->data[j].right = b1->data[i].right;
}
}
for (i=0, j=b2->y-y; i<b2->height; i++,j++)
{
if (b2->data[i].right >= b2->data[i].left)
{
if (present[j])
{
if (result->data[j].left > b2->data[i].left)
result->data[j].left = b2->data[i].left;
if (result->data[j].right < b2->data[i].right)
result->data[j].right = b2->data[i].right;
}
else
{
present[j] = EDGE_LEFT | EDGE_RIGHT;
result->data[j].left = b2->data[i].left;
result->data[j].right = b2->data[i].right;
}
}
}
airbrush_blob_make_convex (result, present);
g_free (present);
return result;
}
/* You must be able to divide TABLE_SIZE with 4*/
#define TABLE_SIZE 256
#define TABLE_QUARTER TABLE_SIZE/4
#define ELLIPSE_SHIFT 2
#define TABLE_SHIFT 14
#define TOTAL_SHIFT (ELLIPSE_SHIFT + TABLE_SHIFT)
static int trig_initialized = 0;
static int trig_table[TABLE_SIZE];
#define POWFAC 0.999
/* Scan convert an ellipse specified by _offsets_ of major and
minor axes, and by center into a airbrush_blob */
/* Warning UGLY code ahead :-)*/
AirBrushBlob *
airbrush_blob_ellipse (double xc, double yc, double xt, double yt, double xr, double yr, double xb, double yb, double xl, double yl)
{
int i;
AirBrushBlob *rma, *rmi, *rtot;
gint maxyma, minyma, maxymi, minymi;
gint step;
double max_radius;
double ma_ang1, ma_ang2;
double x1, x2, y1, y2;
double xtotma, ytotma;
double xcma, ycma, ytma, xrma, ybma, xlma;
double xcmi, ycmi, ytmi, xrmi, ybmi, xlmi;
double mapoint_i, mapoint;
gint xcma_shift, ycma_shift;
gint xcmi_shift, ycmi_shift;
gint ytma_shift, ytmi_shift;
gint xrma_shift, xrmi_shift;
gint ybma_shift, ybmi_shift;
gint xlma_shift, xlmi_shift;
EdgeType *presentma;
EdgeType *presentmi;
if ((yt == yb) && (xr == xl) && (yt == xr))
{
/*Zero*/
ytma = ytmi = xrma = xrmi = ybma = ybmi = xlma = xlmi = yt;
ycma = ycmi = yc;
xcma = xcmi = xc;
}
else if (xr == xl)
{
if (yt > yb)
{
/*South*/
/*The Max circle*/
ytma = ybma = xrma = xlma = xl;
mapoint_i = (((yt * yt) / yb) - yt);
mapoint = mapoint_i * pow(POWFAC, mapoint_i);
xcma = xc;
ycma = yc + mapoint;
/*The Min Circle*/
ytmi = xrmi = ybmi = xlmi = xl/2;
xcmi = xc;
ycmi = yc - mapoint/2;
}
else
{
/*North*/
/*The Max circle*/
ytma = ybma = xrma = xlma = xl;
mapoint_i = (((yb * yb) / yt) - yb);
mapoint = mapoint_i * pow(POWFAC, mapoint_i);
xcma = xc;
ycma = yc - mapoint;
/*The Min Circle*/
ytmi = xrmi = ybmi = xlmi = xl/2;
xcmi = xc;
ycmi = yc + mapoint/2;
}
}
else if (yt == yb)
{
if (xr > xl)
{
/*East*/
/*The Max circle*/
ytma = ybma = xrma = xlma = yt;
mapoint_i = (((xr * xr) /xl) -xr);
mapoint = mapoint_i * pow(POWFAC, mapoint_i);
xcma = mapoint + xc;
ycma = yc;
/*The Min Circle*/
ytmi = ybmi = xrmi = xlmi = yt/2;
xcmi = xc - mapoint/2;
ycmi = yc;
}
else
{
/*West*/
/*The Max circle*/
ytma = ybma = xrma = xlma = yt;
mapoint_i = (((xl * xl) /xr) - xl);
mapoint = mapoint_i * pow(POWFAC, mapoint_i);
xcma = xc - mapoint;
ycma = yc;
/*The Min Circle*/
ytmi = ybmi = xrmi = xlmi = yt/2;
xcmi = xc + mapoint/2;
ycmi = yc;
}
}
else if ((yt > yb) && (xr > xl))
{
/*SouthEast*/
/*The Max circle*/
ma_ang1 = atan(yt/xr);
x1 = cos(ma_ang1) * xl;
y1 = sin(ma_ang1) * yt;
ma_ang2 = M_PI/2 - ma_ang1;
x2 = cos(ma_ang2) * xr;
y2 = sin(ma_ang2) * yb;
xtotma = x1 + x2;
ytotma = y1 + y2;
ytma = ybma = xrma = xlma = hypot(ytotma, xtotma)/2;
mapoint_i = (((yt * yt + xr * xr) / hypot(yb, xl)) - hypot(yt, xr));
mapoint = mapoint_i * pow(POWFAC , mapoint_i);
xcma = xc + (cos(ma_ang1) * mapoint);
ycma = yc + (sin(ma_ang1) * mapoint);
/*The Min Circle*/
ytmi = xrmi = ybmi = xlmi = hypot(yb, xl)/2;
xcmi = xc - (cos(ma_ang1) * mapoint * 0.5);
ycmi = yc - (sin(ma_ang1) * mapoint * 0.5);
}
else if ((yt > yb) && (xl > xr))
{
/*SouthWest*/
/*The Max circle*/
ma_ang1 = atan(yt/xl);
x1 = cos(ma_ang1) * xr;
y1 = sin(ma_ang1) * yt;
ma_ang2 = M_PI/2 - ma_ang1;
x2 = cos(ma_ang2) * xl;
y2 = sin(ma_ang2) * yb;
xtotma = x1 + x2;
ytotma = y1 + y2;
ytma = ybma = xrma = xlma = hypot(ytotma, xtotma)/2;
mapoint_i = (((yt * yt + xl * xl) / hypot(yb, xr)) - hypot(yt, xl));
mapoint = mapoint_i * pow(POWFAC, mapoint_i);
xcma = xc - (cos(ma_ang1) * mapoint);
ycma = yc + (sin(ma_ang1) * mapoint);
/*The Min Circle*/
ytmi = xrmi = ybmi = xlmi = hypot(yb, xr)/2;
xcmi = xc + (cos(ma_ang1) * mapoint * 0.5);
ycmi = yc - (sin(ma_ang1) * mapoint * 0.5);
}
else if ((yb > yt) && (xl > xr))
{
/*NorthWest*/
/*The Max circle*/
ma_ang1 = atan(yb/xl);
x1 = cos(ma_ang1) * xl;
y1 = sin(ma_ang1) * yt;
ma_ang2 = M_PI/2 - ma_ang1;
x2 = cos(ma_ang2) * xr;
y2 = sin(ma_ang2) * yb;
xtotma = x1 + x2;
ytotma = y1 + y2;
ytma = ybma = xrma = xlma = hypot(ytotma, xtotma)/2;
mapoint_i = (((yb * yb + xl * xl) / hypot(yt, xr)) - hypot(yb, xl));
mapoint = mapoint_i * pow(POWFAC, mapoint_i);
xcma = xc - (cos(ma_ang1) * mapoint);
ycma = yc - (sin(ma_ang1) * mapoint);
/*The Min Circle*/
ytmi = xrmi = ybmi = xlmi = hypot(yt, xr)/2;
xcmi = xc + (cos(ma_ang1) * mapoint * 0.5);
ycmi = yc + (sin(ma_ang1) * mapoint * 0.5);
}
else
/*if ((yb > yt) && (xr > xl))*/
{
/*NorthEast*/
/*The Max circle*/
ma_ang1 = atan(yb/xr);
x1 = cos(ma_ang1) * xr;
y1 = sin(ma_ang1) * yt;
ma_ang2 = M_PI/2 - ma_ang1;
x2 = cos(ma_ang2) * xl;
y2 = sin(ma_ang2) * yb;
xtotma = x1 + x2;
ytotma = y1 + y2;
ytma = ybma = xrma = xlma = hypot(ytotma, xtotma)/2;
mapoint_i = (((yb * yb + xr * xr) / hypot(yt, xl)) - hypot(yb, xr));
mapoint = mapoint_i * pow(POWFAC, mapoint_i);
xcma = xc + (cos(ma_ang1) * mapoint);
ycma = yc - (sin(ma_ang1) * mapoint);
/*The Min Circle*/
ytmi = xrmi = ybmi = xlmi = hypot(yt, xl)/2;
xcmi = xc - (cos(ma_ang1) * mapoint * 0.5);
ycmi = yc + (sin(ma_ang1) * mapoint * 0.5);
}
if (ytmi <= 0)
{
ytmi = ybmi = xrmi = xlmi = 1;
}
if (ytma <= 0)
{
ytma = ybma = xrma = xlma = 1;
}
if (!trig_initialized)
{
trig_initialized = 1;
for (i=0; i<256; i++)
trig_table[i] = 0.5 + sin(i * (M_PI / 128.)) * (1 << TABLE_SHIFT);
}
/*Make the Max circle*/
maxyma = ceil (ycma + fabs (ytma));
minyma = floor (ycma - fabs (ybma));
rma = airbrush_blob_new (minyma, maxyma - minyma + 1);
presentma = g_new0 (EdgeType, rma->height);
max_radius = ytma;
step = TABLE_SIZE;
while (step > 1 && (TABLE_SIZE / step < 4*max_radius))
step >>= 1;
/* Fill in the edge points */
xcma_shift = 0.5 + xcma * (1 << TOTAL_SHIFT);
ycma_shift = 0.5 + ycma * (1 << TOTAL_SHIFT);
ytma_shift = 0.5 + ytma * (1 << ELLIPSE_SHIFT);
xrma_shift = 0.5 + xrma * (1 << ELLIPSE_SHIFT);
ybma_shift = 0.5 + ybma * (1 << ELLIPSE_SHIFT);
xlma_shift = 0.5 + xlma * (1 << ELLIPSE_SHIFT);
for (i = 0 ; i < TABLE_SIZE ; i += step)
{
gint x, y, yi, dydi;
gint s = trig_table[i];
gint c = trig_table[(TABLE_SIZE + TABLE_SIZE/4 - i) % TABLE_SIZE];
if (i < TABLE_QUARTER )
{
x = (xcma_shift + c * xrma_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
yi = (ycma_shift + s * ytma_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
y = yi - rma->y;
dydi = 1;
}
else if ( i < (2 * TABLE_QUARTER) )
{
x = (xcma_shift + c * xlma_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
yi = (ycma_shift + s * ytma_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
y = yi - rma->y;
dydi = -1;
}
else if ( i < (3 * TABLE_QUARTER) )
{
x = (xcma_shift + c * xlma_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
yi = (ycma_shift + s * ybma_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
y = yi - rma->y;
dydi = -1;
}
else
{
x = (xcma_shift + c * xrma_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
y = ((ycma_shift + s * ybma_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT) - rma->y;
dydi = 1;
}
if (dydi <= 0) /* left edge */
{
if (presentma[y] & EDGE_LEFT)
{
rma->data[y].left = MIN (rma->data[y].left, x);
}
else
{
presentma[y] |= EDGE_LEFT;
rma->data[y].left = x;
}
}
if (dydi > 0) /* right edge */
{
if (presentma[y] & EDGE_RIGHT)
{
rma->data[y].right = MAX (rma->data[y].right, x);
}
else
{
presentma[y] |= EDGE_RIGHT;
rma->data[y].right = x;
}
}
}
/* Now fill in missing points */
airbrush_blob_fill (rma, presentma);
g_free (presentma);
/*Make the Min circle*/
maxymi = ceil (ycmi + fabs (ytmi));
minymi = floor (ycmi - fabs (ybmi));
rmi = airbrush_blob_new (minymi, maxymi - minymi + 1);
presentmi = g_new0 (EdgeType, rmi->height);
max_radius = ytmi;
step = TABLE_SIZE;
while (step > 1 && (TABLE_SIZE / step < 4*max_radius))
step >>= 1;
/* Fill in the edge points */
xcmi_shift = 0.5 + xcmi * (1 << TOTAL_SHIFT);
ycmi_shift = 0.5 + ycmi * (1 << TOTAL_SHIFT);
ytmi_shift = 0.5 + ytmi * (1 << ELLIPSE_SHIFT);
xrmi_shift = 0.5 + xrmi * (1 << ELLIPSE_SHIFT);
ybmi_shift = 0.5 + ybmi * (1 << ELLIPSE_SHIFT);
xlmi_shift = 0.5 + xlmi * (1 << ELLIPSE_SHIFT);
for (i = 0 ; i < TABLE_SIZE ; i += step)
{
gint x, y, yi, dydi;
gint s = trig_table[i];
gint c = trig_table[(TABLE_SIZE + TABLE_SIZE/4 - i) % TABLE_SIZE];
if (i < TABLE_QUARTER )
{
x = (xcmi_shift + c * xrmi_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
yi = (ycmi_shift + s * ytmi_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
y = yi - rmi->y;
dydi = 1;
}
else if ( i < (2 * TABLE_QUARTER) )
{
x = (xcmi_shift + c * xlmi_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
yi = (ycmi_shift + s * ytmi_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
y = yi - rmi->y;
dydi = -1;
}
else if ( i < (3 * TABLE_QUARTER) )
{
x = (xcmi_shift + c * xlmi_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
yi = (ycmi_shift + s * ybmi_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
y = yi - rmi->y;
dydi = -1;
}
else
{
x = (xcmi_shift + c * xrmi_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT;
y = ((ycmi_shift + s * ybmi_shift +
(1 << (TOTAL_SHIFT - 1))) >> TOTAL_SHIFT) - rmi->y;
dydi = 1;
}
if (dydi <= 0) /* left edge */
{
if (presentmi[y] & EDGE_LEFT)
{
rmi->data[y].left = MIN (rmi->data[y].left, x);
}
else
{
presentmi[y] |= EDGE_LEFT;
rmi->data[y].left = x;
}
}
if (dydi > 0) /* right edge */
{
if (presentmi[y] & EDGE_RIGHT)
{
rmi->data[y].right = MAX (rmi->data[y].right, x);
}
else
{
presentmi[y] |= EDGE_RIGHT;
rmi->data[y].right = x;
}
}
}
/* Now fill in missing points */
airbrush_blob_fill (rmi, presentmi);
g_free (presentmi);
rtot = airbrush_blob_convex_union(rma, rmi);
g_free (rma);
g_free (rmi);
return rtot;
}
void
airbrush_blob_bounds(AirBrushBlob *b, int *x, int *y, int *width, int *height)
{
int i;
int x0, x1, y0, y1;
i = 0;
while (i<b->height && b->data[i].left > b->data[i].right)
i++;
if (i<b->height)
{
y0 = b->y + i;
x0 = b->data[i].left;
x1 = b->data[i].right + 1;
while (i<b->height && b->data[i].left <= b->data[i].right)
{
x0 = MIN(b->data[i].left, x0);
x1 = MAX(b->data[i].right+1, x1);
i++;
}
y1 = b->y + i;
}
else
{
x0 = y0 = 0;
x1 = y1 = 0;
}
*x = x0;
*y = y0;
*width = x1 - x0;
*height = y1 - y0;
}
void
airbrush_blob_dump(AirBrushBlob *b) {
int i,j;
for (i=0; i<b->height; i++)
{
for (j=0;j<b->data[i].left;j++)
putchar(' ');
for (j=b->data[i].left;j<=b->data[i].right;j++)
putchar('*');
putchar('\n');
}
}
/* This is just a first try to see how it works i.e ugly code :-) */
AirBlob *
create_air_blob (double xc,
double yc,
double xt,
double yt,
double xr,
double yr,
double xb,
double yb,
double xl,
double yl,
double direction_abs,
double direction)
{
AirBlob *air_blob;
double ma_ang1, ma_ang2;
double x1, x2, y1, y2;
double xtotma, ytotma;
double xcma, ycma, ytma, xrma, ybma, xlma;
double xcmi, ycmi, ytmi, xrmi, ybmi, xlmi;
double mapoint_i, mapoint;
air_blob = airblob_new(1);
air_blob->direction_abs = direction_abs;
air_blob->direction = direction;
air_blob->ycenter = yc;
air_blob->xcenter = xc;
if ((yt == yb) && (xr == xl) && (yt == xr))
{
/*Zero*/
ytma = ytmi = xrma = xrmi = ybma = ybmi = xlma = xlmi = yt;
ycma = ycmi = yc;
xcma = xcmi = xc;
air_blob->main_line.size = yt;
air_blob->minor_line.size = yt;
air_blob->maincross_line.size = yt * 2;
air_blob->maincross_line.dist = 0.0;
air_blob->minorcross_line.size = yt * 2;
air_blob->minorcross_line.dist = 0.0;
air_blob->direction = M_PI_H;
}
else if (xr == xl)
{
if (yt > yb)
{
/*South*/
/*The Max circle*/
ytma = ybma = xrma = xlma = xl;
mapoint_i = (((yt * yt) / yb) - yt);
mapoint = mapoint_i * pow(POWFAC, mapoint_i);
xcma = xc;
ycma = yc + mapoint;
/*The Min Circle*/
ytmi = xrmi = ybmi = xlmi = xl/2;
xcmi = xc;
ycmi = yc - mapoint/2;
air_blob->main_line.size = mapoint + xl;
air_blob->minor_line.size = mapoint/2 + xl/2;
air_blob->maincross_line.size = xl * 2;
air_blob->maincross_line.dist = mapoint;
air_blob->minorcross_line.size = xl/2;
air_blob->minorcross_line.dist = mapoint/2;
}
else
{
/*North*/
/*The Max circle*/
ytma = ybma = xrma = xlma = xl;
mapoint_i = (((yb * yb) / yt) - yb);
mapoint = mapoint_i * pow(POWFAC, mapoint_i);
xcma = xc;
ycma = yc - mapoint;
/*The Min Circle*/
ytmi = xrmi = ybmi = xlmi = xl/2;
xcmi = xc;
ycmi = yc + mapoint/2;
air_blob->main_line.size = mapoint + xl;
air_blob->minor_line.size = mapoint/2 + xl/2;
air_blob->maincross_line.size = xl * 2;
air_blob->maincross_line.dist = mapoint;
air_blob->minorcross_line.size = xl/2;
air_blob->minorcross_line.dist = mapoint/2;
}
}
else if (yt == yb)
{
if (xr > xl)
{
/*East*/
/*The Max circle*/
ytma = ybma = xrma = xlma = yt;
mapoint_i = (((xr * xr) /xl) -xr);
mapoint = mapoint_i * pow(POWFAC, mapoint_i);
xcma = mapoint + xc;
ycma = yc;
/*The Min Circle*/
ytmi = ybmi = xrmi = xlmi = yt/2;
xcmi = xc - mapoint/2;
ycmi = yc;
air_blob->main_line.size = mapoint + yt;
air_blob->minor_line.size = mapoint/2 + yt/2;
air_blob->maincross_line.size = xl * 2;
air_blob->maincross_line.dist = mapoint;
air_blob->minorcross_line.size = xl/2;
air_blob->minorcross_line.dist = mapoint/2;
}
else
{
/*West*/
/*The Max circle*/
ytma = ybma = xrma = xlma = yt;
mapoint_i = (((xl * xl) /xr) - xl);
mapoint = mapoint_i * pow(POWFAC, mapoint_i);
xcma = xc - mapoint;
ycma = yc;
/*The Min Circle*/
ytmi = ybmi = xrmi = xlmi = yt/2;
xcmi = xc + mapoint/2;
ycmi = yc;
air_blob->main_line.size = mapoint + yt;
air_blob->minor_line.size = mapoint/2 + yt/2;
air_blob->maincross_line.size = xl * 2;
air_blob->maincross_line.dist = mapoint;
air_blob->minorcross_line.size = xl/2;
air_blob->minorcross_line.dist = mapoint/2;
}
}
else if ((yt > yb) && (xr > xl))
{
/*SouthEast*/
/*The Max circle*/
ma_ang1 = atan(yt/xr);
x1 = cos(ma_ang1) * xl;
y1 = sin(ma_ang1) * yt;
ma_ang2 = M_PI/2 - ma_ang1;
x2 = cos(ma_ang2) * xr;
y2 = sin(ma_ang2) * yb;
xtotma = x1 + x2;
ytotma = y1 + y2;
ytma = ybma = xrma = xlma = hypot(ytotma, xtotma)/2;
mapoint_i = (((yt * yt + xr * xr) / hypot(yb, xl)) - hypot(yt, xr));
mapoint = mapoint_i * pow(POWFAC , mapoint_i);
xcma = xc + (cos(ma_ang1) * mapoint);
ycma = yc + (sin(ma_ang1) * mapoint);
/*The Min Circle*/
ytmi = xrmi = ybmi = xlmi = hypot(yb, xl)/2;
xcmi = xc - (cos(ma_ang1) * mapoint * 0.5);
ycmi = yc - (sin(ma_ang1) * mapoint * 0.5);
air_blob->main_line.size = mapoint + xlma;
air_blob->minor_line.size = mapoint/2 + xlmi;
air_blob->maincross_line.size = xlma * 2;
air_blob->maincross_line.dist = mapoint;
air_blob->minorcross_line.size = xlmi;
air_blob->minorcross_line.dist = mapoint/2;
}
else if ((yt > yb) && (xl > xr))
{
/*SouthWest*/
/*The Max circle*/
ma_ang1 = atan(yt/xl);
x1 = cos(ma_ang1) * xr;
y1 = sin(ma_ang1) * yt;
ma_ang2 = M_PI/2 - ma_ang1;
x2 = cos(ma_ang2) * xl;
y2 = sin(ma_ang2) * yb;
xtotma = x1 + x2;
ytotma = y1 + y2;
ytma = ybma = xrma = xlma = hypot(ytotma, xtotma)/2;
mapoint_i = (((yt * yt + xl * xl) / hypot(yb, xr)) - hypot(yt, xl));
mapoint = mapoint_i * pow(POWFAC, mapoint_i);
xcma = xc - (cos(ma_ang1) * mapoint);
ycma = yc + (sin(ma_ang1) * mapoint);
/*The Min Circle*/
ytmi = xrmi = ybmi = xlmi = hypot(yb, xr)/2;
xcmi = xc + (cos(ma_ang1) * mapoint * 0.5);
ycmi = yc - (sin(ma_ang1) * mapoint * 0.5);
air_blob->main_line.size = mapoint + xlma;
air_blob->minor_line.size = mapoint/2 + xlmi;
air_blob->maincross_line.size = xlma * 2;
air_blob->maincross_line.dist = mapoint;
air_blob->minorcross_line.size = xlmi;
air_blob->minorcross_line.dist = mapoint/2;
}
else if ((yb > yt) && (xl > xr))
{
/*NorthWest*/
/*The Max circle*/
ma_ang1 = atan(yb/xl);
x1 = cos(ma_ang1) * xl;
y1 = sin(ma_ang1) * yt;
ma_ang2 = M_PI/2 - ma_ang1;
x2 = cos(ma_ang2) * xr;
y2 = sin(ma_ang2) * yb;
xtotma = x1 + x2;
ytotma = y1 + y2;
ytma = ybma = xrma = xlma = hypot(ytotma, xtotma)/2;
mapoint_i = (((yb * yb + xl * xl) / hypot(yt, xr)) - hypot(yb, xl));
mapoint = mapoint_i * pow(POWFAC, mapoint_i);
xcma = xc - (cos(ma_ang1) * mapoint);
ycma = yc - (sin(ma_ang1) * mapoint);
/*The Min Circle*/
ytmi = xrmi = ybmi = xlmi = hypot(yt, xr)/2;
xcmi = xc + (cos(ma_ang1) * mapoint * 0.5);
ycmi = yc + (sin(ma_ang1) * mapoint * 0.5);
air_blob->main_line.size = mapoint + xlma;
air_blob->minor_line.size = mapoint/2 + xlmi;
air_blob->maincross_line.size = xlma * 2;
air_blob->maincross_line.dist = mapoint;
air_blob->minorcross_line.size = xlmi;
air_blob->minorcross_line.dist = mapoint/2;
}
else
/*if ((yb > yt) && (xr > xl))*/
{
/*NorthEast*/
/*The Max circle*/
ma_ang1 = atan(yb/xr);
x1 = cos(ma_ang1) * xr;
y1 = sin(ma_ang1) * yt;
ma_ang2 = M_PI/2 - ma_ang1;
x2 = cos(ma_ang2) * xl;
y2 = sin(ma_ang2) * yb;
xtotma = x1 + x2;
ytotma = y1 + y2;
ytma = ybma = xrma = xlma = hypot(ytotma, xtotma)/2;
mapoint_i = (((yb * yb + xr * xr) / hypot(yt, xl)) - hypot(yb, xr));
mapoint = mapoint_i * pow(POWFAC, mapoint_i);
xcma = xc + (cos(ma_ang1) * mapoint);
ycma = yc - (sin(ma_ang1) * mapoint);
/*The Min Circle*/
ytmi = xrmi = ybmi = xlmi = hypot(yt, xl)/2;
xcmi = xc - (cos(ma_ang1) * mapoint * 0.5);
ycmi = yc + (sin(ma_ang1) * mapoint * 0.5);
air_blob->main_line.size = mapoint + xlma;
air_blob->minor_line.size = mapoint/2 + xlmi;
air_blob->maincross_line.size = xlma * 2;
air_blob->maincross_line.dist = mapoint;
air_blob->minorcross_line.size = xlmi;
air_blob->minorcross_line.dist = mapoint/2;
}
return air_blob;
}
AirLine *
create_air_line(AirBlob *airblob)
{
int i;
double xcenter, ycenter;
double direction;
double masupport, misupport;
double ma_angsupport, mi_angsupport, iang;
int min_x, max_x;
int min_y, max_y;
AirLine *airline;
/* Yes I know I can do a cal of number of lines, but it is for
the moment much easier to just set a side mem for 16 lines
*/
airline = airline_new(1);
xcenter = airblob->xcenter;
ycenter = airblob->ycenter;
airline->xcenter = xcenter/SUBSAMPLE;
airline->ycenter = ycenter/SUBSAMPLE;
direction = airblob->direction_abs;
if(direction == 0.0)
{
airline->line[0].x = (xcenter + airblob->maincross_line.dist)/SUBSAMPLE;
airline->line[0].y = (ycenter - airblob->maincross_line.size/2)/SUBSAMPLE;
airline->line[1].x = (xcenter - airblob->minorcross_line.dist)/SUBSAMPLE;
airline->line[1].y = (ycenter + airblob->minorcross_line.size/2)/SUBSAMPLE;
airline->line[2].x = (xcenter + airblob->main_line.size)/SUBSAMPLE;
airline->line[2].y = (ycenter)/SUBSAMPLE;
airline->line[3].x = (xcenter - airblob->minor_line.size)/SUBSAMPLE;
airline->line[3].y = (ycenter)/SUBSAMPLE;
airline->line[4].x = (xcenter + airblob->maincross_line.dist)/SUBSAMPLE;
airline->line[4].y = (ycenter + airblob->maincross_line.size/2)/SUBSAMPLE;
airline->line[5].x = (xcenter - airblob->minorcross_line.dist)/SUBSAMPLE;
airline->line[5].y = (ycenter - airblob->minorcross_line.size/2)/SUBSAMPLE;
airline->nlines = 6;
}
else if(direction == M_PI_H)
{
airline->line[0].x = (xcenter - airblob->maincross_line.size/2)/SUBSAMPLE;
airline->line[0].y = (ycenter - airblob->maincross_line.dist)/SUBSAMPLE;
airline->line[1].x = (xcenter + airblob->minorcross_line.dist)/SUBSAMPLE;
airline->line[1].y = (ycenter + airblob->minorcross_line.size/2)/SUBSAMPLE;
airline->line[2].x = (xcenter)/SUBSAMPLE;
airline->line[2].y = (ycenter - airblob->main_line.size)/SUBSAMPLE;
airline->line[3].x = (xcenter)/SUBSAMPLE;
airline->line[3].y = (ycenter + airblob->minor_line.size)/SUBSAMPLE;
airline->line[4].x = (xcenter + airblob->maincross_line.dist)/SUBSAMPLE;
airline->line[4].y = (ycenter - airblob->maincross_line.size/2)/SUBSAMPLE;
airline->line[5].x = (xcenter - airblob->minorcross_line.dist)/SUBSAMPLE;
airline->line[5].y = (ycenter + airblob->minorcross_line.size/2)/SUBSAMPLE;
airline->nlines = 6;
}
else if(direction == M_PI)
{
airline->line[0].x = (xcenter - airblob->maincross_line.dist)/SUBSAMPLE;
airline->line[0].y = (ycenter + airblob->maincross_line.size/2)/SUBSAMPLE;
airline->line[1].x = (xcenter + airblob->minorcross_line.dist)/SUBSAMPLE;
airline->line[1].y = (ycenter - airblob->minorcross_line.size/2)/SUBSAMPLE;
airline->line[2].x = (xcenter - airblob->main_line.size)/SUBSAMPLE;
airline->line[2].y = (ycenter)/SUBSAMPLE;
airline->line[3].x = (xcenter + airblob->minor_line.size)/SUBSAMPLE;
airline->line[3].y = (ycenter)/SUBSAMPLE;
airline->line[4].x = (xcenter - airblob->maincross_line.dist)/SUBSAMPLE;
airline->line[4].y = (ycenter - airblob->maincross_line.size/2)/SUBSAMPLE;
airline->line[5].x = (xcenter + airblob->minorcross_line.dist)/SUBSAMPLE;
airline->line[5].y = (ycenter + airblob->minorcross_line.size/2)/SUBSAMPLE;
airline->nlines = 6;
}
else if(direction == -M_PI_H)
{
airline->line[0].x = (xcenter - airblob->maincross_line.dist)/SUBSAMPLE;
airline->line[0].y = (ycenter + airblob->maincross_line.size/2)/SUBSAMPLE;
airline->line[1].x = (xcenter + airblob->minorcross_line.dist)/SUBSAMPLE;
airline->line[1].y = (ycenter - airblob->minorcross_line.size/2)/SUBSAMPLE;
airline->line[2].x = (xcenter)/SUBSAMPLE;
airline->line[2].y = (ycenter + airblob->main_line.size)/SUBSAMPLE;
airline->line[3].x = (xcenter)/SUBSAMPLE;
airline->line[3].y = (ycenter - airblob->minor_line.size)/SUBSAMPLE;
airline->line[4].x = (xcenter + airblob->maincross_line.dist)/SUBSAMPLE;
airline->line[4].y = (ycenter + airblob->maincross_line.size/2)/SUBSAMPLE;
airline->line[5].x = (xcenter - airblob->minorcross_line.dist)/SUBSAMPLE;
airline->line[5].y = (ycenter - airblob->minorcross_line.size/2)/SUBSAMPLE;
}
else if(direction == -M_PI)
{
airline->line[0].x = (xcenter - airblob->maincross_line.dist)/SUBSAMPLE;
airline->line[0].y = (ycenter + airblob->maincross_line.size/2)/SUBSAMPLE;
airline->line[1].x = (xcenter + airblob->minorcross_line.dist)/SUBSAMPLE;
airline->line[1].y = (ycenter - airblob->minorcross_line.size/2)/SUBSAMPLE;
airline->line[2].x = (xcenter - airblob->main_line.size)/SUBSAMPLE;
airline->line[2].y = (ycenter)/SUBSAMPLE;
airline->line[3].x = (xcenter + airblob->minor_line.size)/SUBSAMPLE;
airline->line[3].y = (ycenter)/SUBSAMPLE;
airline->line[4].x = (xcenter - airblob->maincross_line.dist)/SUBSAMPLE;
airline->line[4].y = (ycenter - airblob->maincross_line.size/2)/SUBSAMPLE;
airline->line[5].x = (xcenter + airblob->minorcross_line.dist)/SUBSAMPLE;
airline->line[5].y = (ycenter + airblob->minorcross_line.size/2)/SUBSAMPLE;
airline->nlines = 6;
}
else if ((direction < M_PI) && (direction > M_PI_H))
{
masupport = hypot(airblob->maincross_line.dist, airblob->maincross_line.size/2);
misupport = hypot(airblob->minorcross_line.dist,airblob->minorcross_line.size/2);
ma_angsupport = atan(airblob->maincross_line.size/2/airblob->maincross_line.dist);
mi_angsupport = atan(airblob->minorcross_line.size/2/airblob->minorcross_line.dist);
iang = airblob->direction_abs - M_PI_H;
airline->line[0].x = (xcenter - sin(iang + ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[0].y = (ycenter - cos(iang + ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[1].x = (xcenter + sin(iang + mi_angsupport) * misupport)/SUBSAMPLE;
airline->line[1].y = (ycenter + cos(iang + mi_angsupport) * misupport)/SUBSAMPLE;
airline->line[2].x = (xcenter - sin(iang) * airblob->main_line.size)/SUBSAMPLE;
airline->line[2].y = (ycenter - cos(iang) * airblob->main_line.size)/SUBSAMPLE;
airline->line[3].x = (xcenter + sin(iang) * airblob->minor_line.size)/SUBSAMPLE;
airline->line[3].y = (ycenter + cos(iang) * airblob->minor_line.size)/SUBSAMPLE;
airline->line[4].x = (xcenter - sin(iang - ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[4].y = (ycenter - cos(iang - ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[5].x = (xcenter + sin(iang - mi_angsupport) * misupport)/SUBSAMPLE;
airline->line[5].y = (ycenter + cos(iang - mi_angsupport) * misupport)/SUBSAMPLE;
airline->line[6].x = (xcenter - sin(iang + ma_angsupport/2.) * (masupport + (airblob->main_line.size - masupport)/2.0))/SUBSAMPLE;
airline->line[6].y = (ycenter - cos(iang + ma_angsupport/2.) * (masupport + (airblob->main_line.size - masupport)/2.0))/SUBSAMPLE;
airline->line[7].x = (xcenter - sin(iang - ma_angsupport/2.) * (masupport + (airblob->main_line.size - masupport)/2.0))/SUBSAMPLE;
airline->line[7].y = (ycenter - cos(iang - ma_angsupport/2.) * (masupport + (airblob->main_line.size - masupport)/2.0))/SUBSAMPLE;
airline->nlines = 8;
}
else if ((direction < M_PI_H) && (direction > 0.0))
{
masupport = hypot(airblob->maincross_line.dist, airblob->maincross_line.size/2);
misupport = hypot(airblob->minorcross_line.dist,airblob->minorcross_line.size/2);
ma_angsupport = atan(airblob->maincross_line.size/2/airblob->maincross_line.dist);
mi_angsupport = atan(airblob->minorcross_line.size/2/airblob->minorcross_line.dist);
iang = airblob->direction_abs;
airline->line[0].x = (xcenter + cos(iang + ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[0].y = (ycenter - sin(iang + ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[1].x = (xcenter - cos(iang + mi_angsupport) * misupport)/SUBSAMPLE;
airline->line[1].y = (ycenter + sin(iang + mi_angsupport) * misupport)/SUBSAMPLE;
airline->line[2].x = (xcenter + cos(iang) * airblob->main_line.size)/SUBSAMPLE;
airline->line[2].y = (ycenter - sin(iang) * airblob->main_line.size)/SUBSAMPLE;
airline->line[3].x = (xcenter - cos(iang) * airblob->minor_line.size)/SUBSAMPLE;
airline->line[3].y = (ycenter + sin(iang) * airblob->minor_line.size)/SUBSAMPLE;
airline->line[4].x = (xcenter + cos(iang - ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[4].y = (ycenter - sin(iang - ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[5].x = (xcenter - cos(iang - mi_angsupport) * misupport)/SUBSAMPLE;
airline->line[5].y = (ycenter + sin(iang - mi_angsupport) * misupport)/SUBSAMPLE;
airline->line[6].x = (xcenter + cos(iang + ma_angsupport/2.) * (masupport + (airblob->main_line.size - masupport)/2.0))/SUBSAMPLE;
airline->line[6].y = (ycenter - sin(iang + ma_angsupport/2.) * (masupport + (airblob->main_line.size - masupport)/2.0))/SUBSAMPLE;
airline->line[7].x = (xcenter + cos(iang - ma_angsupport/2.) * (masupport + (airblob->main_line.size - masupport)/2.0))/SUBSAMPLE;
airline->line[7].y = (ycenter - sin(iang - ma_angsupport/2.) * (masupport + (airblob->main_line.size - masupport)/2.0))/SUBSAMPLE;
airline->nlines = 8;
}
else if ((direction < 0.0) && (direction > -M_PI_H))
{
masupport = hypot(airblob->maincross_line.dist, airblob->maincross_line.size/2);
misupport = hypot(airblob->minorcross_line.dist,airblob->minorcross_line.size/2);
ma_angsupport = atan(airblob->maincross_line.size/2/airblob->maincross_line.dist);
mi_angsupport = atan(airblob->minorcross_line.size/2/airblob->minorcross_line.dist);
iang = fabs(airblob->direction_abs);
airline->line[0].x = (xcenter + cos(iang + ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[0].y = (ycenter + sin(iang + ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[1].x = (xcenter - cos(iang + mi_angsupport) * misupport)/SUBSAMPLE;
airline->line[1].y = (ycenter - sin(iang + mi_angsupport) * misupport)/SUBSAMPLE;
airline->line[2].x = (xcenter + cos(iang) * airblob->main_line.size)/SUBSAMPLE;
airline->line[2].y = (ycenter + sin(iang) * airblob->main_line.size)/SUBSAMPLE;
airline->line[3].x = (xcenter - cos(iang) * airblob->minor_line.size)/SUBSAMPLE;
airline->line[3].y = (ycenter - sin(iang) * airblob->minor_line.size)/SUBSAMPLE;
airline->line[4].x = (xcenter + cos(iang - ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[4].y = (ycenter + sin(iang - ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[5].x = (xcenter - cos(iang - mi_angsupport) * misupport)/SUBSAMPLE;
airline->line[5].y = (ycenter - sin(iang - mi_angsupport) * misupport)/SUBSAMPLE;
airline->nlines = 6;
}
else if ((direction < -M_PI_H) && (direction > -M_PI))
{
masupport = hypot(airblob->maincross_line.dist, airblob->maincross_line.size/2);
misupport = hypot(airblob->minorcross_line.dist,airblob->minorcross_line.size/2);
ma_angsupport = atan(airblob->maincross_line.size/2/airblob->maincross_line.dist);
mi_angsupport = atan(airblob->minorcross_line.size/2/airblob->minorcross_line.dist);
iang = fabs(airblob->direction_abs) - M_PI_H;
airline->line[0].x = (xcenter - sin(iang + ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[0].y = (ycenter + cos(iang + ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[1].x = (xcenter + sin(iang + mi_angsupport) * misupport)/SUBSAMPLE;
airline->line[1].y = (ycenter - cos(iang + mi_angsupport) * misupport)/SUBSAMPLE;
airline->line[2].x = (xcenter - sin(iang) * airblob->main_line.size)/SUBSAMPLE;
airline->line[2].y = (ycenter + cos(iang) * airblob->main_line.size)/SUBSAMPLE;
airline->line[3].x = (xcenter + sin(iang) * airblob->minor_line.size)/SUBSAMPLE;
airline->line[3].y = (ycenter - cos(iang) * airblob->minor_line.size)/SUBSAMPLE;
airline->line[4].x = (xcenter - sin(iang - ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[4].y = (ycenter + cos(iang - ma_angsupport) * masupport)/SUBSAMPLE;
airline->line[5].x = (xcenter + sin(iang - mi_angsupport) * misupport)/SUBSAMPLE;
airline->line[5].y = (ycenter - cos(iang - mi_angsupport) * misupport)/SUBSAMPLE;
airline->nlines = 6;
}
else
{
printf("Hmm a bug in the create_air_line");
}
min_x = max_x = airline->xcenter;
min_y = max_y = airline->ycenter;
for (i=0; i < airline->nlines ; i++)
{
min_x = MIN(airline->line[i].x, min_x);
max_x = MAX(airline->line[i].x, max_x);
min_y = MIN(airline->line[i].y, min_y);
max_y = MAX(airline->line[i].y, max_y);
}
airline->width = max_x - min_x + 1;
airline->height = max_y - min_y + 1;
airline->min_x = min_x;
airline->min_y = min_y;
airline->max_x = max_x;
airline->max_y = max_y;
return airline;
}
AirBlob *
trans_air_blob(AirBlob *airblob_last, AirBlob *airblob_present, double dist, int xcen, int ycen)
{
AirBlob *trans_airblob;
double direction_last_abs, direction_present_abs;
double idirection_abs;
double direction_last, direction_present;
double idirection;
double main_line_present, main_line_last;
double minor_line_present, minor_line_last;
double maincross_line_dist_present, maincross_line_dist_last;
double minorcross_line_dist_present, minorcross_line_dist_last;
double maincross_line_size_present, maincross_line_size_last;
double minorcross_line_size_present, minorcross_line_size_last;
trans_airblob = airblob_new(1);
direction_last_abs = airblob_last->direction_abs + M_PI;
direction_present_abs = airblob_present->direction_abs + M_PI;
idirection_abs = direction_present_abs - direction_last_abs;
direction_last = airblob_last->direction + M_PI_H;
direction_present = airblob_present->direction + M_PI_H;
idirection = direction_present - direction_last;
main_line_present = airblob_present->main_line.size;
main_line_last = airblob_last->main_line.size;
minor_line_present = airblob_present->minor_line.size;
minor_line_last = airblob_last->minor_line.size;
maincross_line_dist_present = airblob_present->maincross_line.dist;
maincross_line_size_present = airblob_present->maincross_line.size;
minorcross_line_dist_present = airblob_present->minorcross_line.dist;
minorcross_line_size_present = airblob_present->minorcross_line.size;
maincross_line_dist_last = airblob_last->maincross_line.dist;
maincross_line_size_last = airblob_last->maincross_line.size;
minorcross_line_dist_last = airblob_last->minorcross_line.dist;
minorcross_line_size_last = airblob_last->minorcross_line.size;
/*
Now we have to guess a little :-). Why?
Well we can't know if the users is painting
up/down or if she is painting a circle at high speed.
As you may notice it be so that the last airblob has
a direction more or less M_PI rad differernt from the
present airblob. But we can't know if she tured the
airbrush quickly (so that there was no mouse capture
during the turn) or if she paints just up and down the
same direction.
There for we guess that we want to pait up and down
when the diff in direction is bigger than 171 deg and
smaller than 189 deg.
*/
if ((fabs(idirection_abs) > (M_PI - 0.1571)) && (fabs(idirection_abs) < (M_PI + 0.1571)))
{
/* We asume that the artist meant to paint in a "strait line" by just tilting the airbrush*/
idirection_abs = idirection_abs - M_PI;
if ((idirection_abs * dist) > (idirection_abs/2))
{
if ((direction_present_abs - idirection_abs * dist) > 2 * M_PI)
{
trans_airblob->direction_abs = direction_present_abs - idirection_abs * dist - 2 * M_PI - M_PI;
}
else if ((direction_present_abs - idirection_abs * dist) < 0.0)
{
trans_airblob->direction_abs = direction_present_abs - idirection_abs * dist + 2 * M_PI - M_PI;
}
else
{
trans_airblob->direction_abs = direction_present_abs - idirection_abs * dist - M_PI;
}
}
else
{
if ((direction_present_abs + idirection_abs * dist) > 2 * M_PI)
{
trans_airblob->direction_abs = direction_present_abs + idirection_abs * dist - 2 * M_PI - M_PI;
}
else if ((direction_present_abs + idirection_abs * dist) < 0.0)
{
trans_airblob->direction_abs = direction_present_abs + idirection_abs * dist + 2 * M_PI - M_PI;
}
else
{
trans_airblob->direction_abs = direction_present_abs + idirection_abs * dist - M_PI;
}
}
trans_airblob->main_line.size = main_line_last + ((minor_line_present - main_line_last) * dist);
trans_airblob->minor_line.size = minor_line_last + ((main_line_present - minor_line_last) * dist);
trans_airblob->maincross_line.dist = maincross_line_dist_last + ((minorcross_line_dist_present - maincross_line_dist_last) * dist);
trans_airblob->maincross_line.size = maincross_line_size_last + ((minorcross_line_size_present - maincross_line_size_last) * dist);
trans_airblob->minorcross_line.dist = minorcross_line_dist_last + ((maincross_line_dist_present - minorcross_line_dist_last) * dist);
trans_airblob->minorcross_line.size = minorcross_line_size_last + ((maincross_line_size_present - minorcross_line_size_last) * dist);
}
else if (fabs(idirection_abs) < (M_PI - 0.1571))
{
if ((direction_last_abs + idirection_abs * dist) > 2*M_PI)
{
trans_airblob->direction_abs = direction_last_abs + idirection_abs * dist - 2 * M_PI - M_PI;
}
else if((direction_last_abs + idirection_abs * dist) < 0.0)
{
trans_airblob->direction_abs = direction_last_abs + idirection_abs * dist + 2 * M_PI - M_PI;
}
else
{
trans_airblob->direction_abs = direction_last_abs + idirection_abs * dist - M_PI;
}
trans_airblob->main_line.size = main_line_last + ((main_line_present - main_line_last) * dist);
trans_airblob->minor_line.size = minor_line_last + ((minor_line_present - minor_line_last) * dist);
trans_airblob->maincross_line.dist = maincross_line_dist_last + ((maincross_line_dist_present - maincross_line_dist_last) * dist);
trans_airblob->maincross_line.size = maincross_line_size_last + ((maincross_line_size_present - maincross_line_size_last) * dist);
trans_airblob->minorcross_line.dist = minorcross_line_dist_last + ((minorcross_line_dist_present - minorcross_line_dist_last) * dist);
trans_airblob->minorcross_line.size = minorcross_line_size_last + ((minorcross_line_size_present - minorcross_line_size_last) * dist);
}
else
{
/* We asume that the artist always travels the shortest way around the "clock" */
idirection_abs = idirection_abs - M_PI;
if ((direction_last_abs + idirection_abs * dist) > 2*M_PI)
{
trans_airblob->direction_abs = direction_last_abs + idirection_abs * dist - 2 * M_PI - M_PI;
}
else if((direction_last_abs + idirection_abs * dist) < 0.0)
{
trans_airblob->direction_abs = direction_last_abs + idirection_abs * dist + 2 * M_PI - M_PI;
}
else
{
trans_airblob->direction_abs = direction_last_abs + idirection_abs * dist - M_PI;
}
trans_airblob->main_line.size = main_line_last + ((main_line_present - main_line_last) * dist);
trans_airblob->minor_line.size = minor_line_last + ((minor_line_present - minor_line_last) * dist);
trans_airblob->maincross_line.dist = maincross_line_dist_last + ((maincross_line_dist_present - maincross_line_dist_last) * dist);
trans_airblob->maincross_line.size = maincross_line_size_last + ((maincross_line_size_present - maincross_line_size_last) * dist);
trans_airblob->minorcross_line.dist = minorcross_line_dist_last + ((minorcross_line_dist_present - minorcross_line_dist_last) * dist);
trans_airblob->minorcross_line.size = minorcross_line_size_last + ((minorcross_line_size_present - minorcross_line_size_last) * dist);
}
trans_airblob->xcenter = xcen * SUBSAMPLE;
trans_airblob->ycenter = ycen * SUBSAMPLE;
return trans_airblob;
}
int
number_of_steps(int x0, int y0, int x1, int y1)
{
int dx, dy;
dx = abs(x0 - x1);
dy = abs(y0 - y1);
if (dy > dx)
{
return dy + 1;
}
else
{
return dx + 1;
}
}