home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DOS/V Power Report 1997 March
/
VPR9703A.ISO
/
VPR_DATA
/
DOGA
/
SOURCES
/
PASM.LZH
/
POLYLINE.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-10
|
10KB
|
338 lines
#include <math.h>
#include <string.h>
#include "polyline.h"
#include "suflib.h"
#include "log.h"
PointID PolyData::AddPoint(int x, int y, int z)
{
if (allocpoints <= points) {
PolyPoint *np = new PolyPoint[allocpoints + POLYALLOCUNIT];
memcpy(np, point, sizeof(PolyPoint) * allocpoints);
delete [] point;
point = np;
allocpoints += POLYALLOCUNIT;
}
point[points].x = x;
point[points].y = y;
point[points].z = z;
return points++;
}
void PolyData::RemovePoint(PointID pid)
{
if (pid >= 0 && pid == points-1) {
points--;
}
}
void PolyData::AddLine(PointID p1, PointID p2, void *id)
{
int i;
if (p1 > p2) {i = p1; p1 = p2; p2 = i;}
if (point[p1].z <= 0
|| point[p2].z <= 0
|| (point[p1].x == point[p2].x && point[p1].y == point[p2].y)
|| (point[p1].x < 0 && point[p2].x < 0)
|| (point[p1].x >= ScreenWidth && point[p2].x >= ScreenWidth)
|| (point[p1].y < 0 && point[p2].y < 0)
|| (point[p1].y >= ScreenHeight && point[p2].y >= ScreenHeight)) {
return;
}
for (i = 0; i < lines; ++i) {
if (line[i].p1 == p1 && line[i].p2 == p2) {
return;
}
}
if (alloclines <= lines) {
PolyLine *nl = new PolyLine[alloclines+ POLYALLOCUNIT];
memcpy(nl, line, sizeof(PolyLine) * alloclines);
delete [] line;
line = nl;
alloclines += POLYALLOCUNIT;
}
line[lines].p1 = p1;
line[lines].p2 = p2;
line[lines].id = id;
lines++;
}
int PolyData::AddPolyClip(int *ps, int offset)
{
int flag;
flag = 0;
if (ScreenWidth <= 0 || ScreenHeight <= 0) {
return TRUE;
}
for (int i = 0; ps[i] != POLY_SEPARATER; ++i) {
if (point[ps[i]+offset].z <= 0)return FALSE;
if (point[ps[i]+offset].x >= 0) flag |= 1;
if (point[ps[i]+offset].x < ScreenWidth) flag |= 2;
if (point[ps[i]+offset].y >= 0) flag |= 4;
if (point[ps[i]+offset].y < ScreenHeight) flag |= 8;
// if (point[ps[i]+offset].z > 0) flag |= 16;
}
if (flag != 15) {
return FALSE;
}
return TRUE;
}
void PolyData::AddPoly(int *ps, int offset, void *id)
{
if (AddPolyClip(ps, offset) == FALSE) {
return;
}
poly[polys].point = pointbuf + pointbufs;
poly[polys].minx = poly[polys].maxx = point[ps[0]+offset].x;
poly[polys].miny = poly[polys].maxy = point[ps[0]+offset].y;
poly[polys].minz = poly[polys].maxz = point[ps[0]+offset].z;
for (int i = 0; ps[i] != POLY_SEPARATER; ++i) {
if (poly[polys].maxx < point[ps[i]+offset].x) poly[polys].maxx = point[ps[i]+offset].x;
if (poly[polys].minx > point[ps[i]+offset].x) poly[polys].minx = point[ps[i]+offset].x;
if (poly[polys].maxy < point[ps[i]+offset].y) poly[polys].maxy = point[ps[i]+offset].y;
if (poly[polys].miny > point[ps[i]+offset].y) poly[polys].miny = point[ps[i]+offset].y;
if (poly[polys].maxz < point[ps[i]+offset].z) poly[polys].maxz = point[ps[i]+offset].z;
if (poly[polys].minz > point[ps[i]+offset].z) poly[polys].minz = point[ps[i]+offset].z;
poly[polys].point[i] = ps[i] + offset;
}
poly[polys].points = i;
poly[polys].id = id;
pointbufs += i;
polys++;
}
void PolyData::AddPolyInv(int *ps, int offset, void *id)
{
if (AddPolyClip(ps, offset) == FALSE) {
return;
}
poly[polys].point = pointbuf + pointbufs;
poly[polys].minx = poly[polys].maxx = point[ps[0]+offset].x;
poly[polys].miny = poly[polys].maxy = point[ps[0]+offset].y;
poly[polys].minz = poly[polys].maxz = point[ps[0]+offset].z;
for (int i = 0; ps[i] != POLY_SEPARATER; ++i)
;
i--;
for (int j = 0; i >= 0; --i, ++j) {
if (poly[polys].maxx < point[ps[i]+offset].x) poly[polys].maxx = point[ps[i]+offset].x;
if (poly[polys].minx > point[ps[i]+offset].x) poly[polys].minx = point[ps[i]+offset].x;
if (poly[polys].maxy < point[ps[i]+offset].y) poly[polys].maxy = point[ps[i]+offset].y;
if (poly[polys].miny > point[ps[i]+offset].y) poly[polys].miny = point[ps[i]+offset].y;
if (poly[polys].maxz < point[ps[i]+offset].z) poly[polys].maxz = point[ps[i]+offset].z;
if (poly[polys].minz > point[ps[i]+offset].z) poly[polys].minz = point[ps[i]+offset].z;
poly[polys].point[j] = ps[i] + offset;
}
poly[polys].points = j;
poly[polys].id = id;
pointbufs += j;
polys++;
}
void PolyData::ConvertLines(void)
{
for (int p = 0; p < polys; ++p) {
Poly *np = poly + p;
for (int i = 0; i < np->points-1; ++i) {
AddLine(np->point[i], np->point[i+1], np->id);
}
AddLine(np->point[i], np->point[0], np->id);
}
for (int i = 0; i < polys; ++i) {
Poly *np = poly + i;
ConvertLine(np);
}
}
int PolyData::IsOutside(PointID p, PointID p1, PointID p2)
{
// PolyPoint *p1 = &point[pid[0]+offp];
// PolyPoint *p2 = &point[pid[1]+offp];
// PolyPoint *p3 = &point[pid[2]+offp];
// long m = (p1->x-p2->x)*(p3->y-p2->y) - (p1->y-p2->y)*(p3->x-p2->x);
if (p < 0) {
return TRUE;
}
if ((long)(point[p1].x-point[p2].x) * (long)(point[p].y-point[p2].y)
- (long)(point[p1].y-point[p2].y) * (long)(point[p].x-point[p2].x) > 0) {
return FALSE;
}
return TRUE;
}
double PolyData::TriangleCrossRate(PointID l1, PointID l2, PointID p1, PointID p2, PointID p3)
{
double delta;
double v1x, v1y, v1z, v2x, v2y, v2z, ux, uy, uz;
v1x = point[p1].x - point[p2].x;
v1y = point[p1].y - point[p2].y;
v1z = point[p1].z - point[p2].z;
v2x = point[p3].x - point[p2].x;
v2y = point[p3].y - point[p2].y;
v2z = point[p3].z - point[p2].z;
ux = point[l2].x - point[l1].x;
uy = point[l2].y - point[l1].y;
uz = point[l2].z - point[l1].z;
delta = v1x * v2y * uz + v1y * v2z * ux + v1z * v2x * uy
- v1x * v2z * uy - v1y * v2x * uz - v1z * v2y * ux;
if (-1 <= delta && delta <= 1) {
return 1.0;
}
double m;
m = (v1y * v2z - v1z * v2y) * (point[l1].x - point[p2].x)
- (v1x * v2z - v1z * v2x) * (point[l1].y - point[p2].y)
+ (v1x * v2y - v1y * v2x) * (point[l1].z - point[p2].z);
m = - m / delta;
return m;
}
int PolyData::TriangleIsFront(PointID p, PointID p1, PointID p2, PointID p3)
{
long delta;
long v1x, v1y, v1z, v2x, v2y, v2z, dx, dy;
v1x = point[p1].x - point[p2].x;
v1y = point[p1].y - point[p2].y;
v1z = point[p1].z - point[p2].z;
v2x = point[p3].x - point[p2].x;
v2y = point[p3].y - point[p2].y;
v2z = point[p3].z - point[p2].z;
dx = point[p].x - point[p2].x;
dy = point[p].y - point[p2].y;
delta = v1x * v2y - v1y * v2x;
if (delta == 0) {
return TRUE;
}
double k, l;
k = (double)( v2y * dx - v2x * dy) / (double)delta;
l = (double)(-v1y * dx + v1x * dy) / (double)delta;
double z = point[p2].z + k * v1z + l * v2z;
if (z - 1.0 <= (double)point[p].z) {
return TRUE;
}
return FALSE;
}
double PolyData::CrossRate(PointID l1, PointID l2, PointID p1, PointID p2)
{
long dx, dy, lx, ly, lz, px, py, pz;
lx = point[l2].x - point[l1].x;
ly = point[l2].y - point[l1].y;
lz = point[l2].z - point[l1].z;
px = point[p2].x - point[p1].x;
py = point[p2].y - point[p1].y;
pz = point[p2].z - point[p1].z;
dx = point[p1].x - point[l1].x;
dy = point[p1].y - point[l1].y;
long delta = lx*py - ly * px;
if (delta == 0) return -1.0;
double k, l;
k = (double)(py * dx - px * dy) / (double)delta;
l = (double)(ly * dx - lx * dy) / (double)delta;
if (l <= 0 || l >= 1.0) {
return -1;
}
if (point[l1].z + k * lz >= point[p1].z + l * pz) {
return -1;
}
return k;
}
void PolyData::ConvertLine(Poly *np)
{
int maxlines;
maxlines = lines;
for (int i = 0; i < maxlines; ++i) {
int p1outside, p2outside, p3outside;
PointID p1 = line[i].p1;
PointID p2 = line[i].p2;
PointID p3 = -1;
if (p1 < 0 || p2 < 0
|| (np->maxz < point[p1].z && np->maxz < point[p2].z)
|| (np->minx > point[p1].x && np->minx > point[p2].x)
|| (np->maxx < point[p1].x && np->maxx < point[p2].x)
|| (np->miny > point[p1].y && np->miny > point[p2].y)
|| (np->maxy < point[p1].y && np->maxy < point[p2].y)) {
continue;
}
p1outside = TriangleIsFront(p1, np->point[0], np->point[1], np->point[2]);
p2outside = TriangleIsFront(p2, np->point[0], np->point[1], np->point[2]);
if (p1outside && p2outside) {
continue;
}
int xd = point[p2].x - point[p1].x;
int yd = point[p2].y - point[p1].y;
int zd = point[p2].z - point[p1].z;
double rate = TriangleCrossRate(p1, p2, np->point[0], np->point[1], np->point[2]);
if (0.0 < rate && rate < 1.0) {
p3 = AddPoint(point[p1].x + xd * rate, point[p1].y + yd * rate, point[p1].z + zd * rate);
}
p1outside |= IsOutside(p1, np->point[np->points-1], np->point[0]);
p2outside |= IsOutside(p2, np->point[np->points-1], np->point[0]);
p3outside = IsOutside(p3, np->point[np->points-1], np->point[0]);
double r1 = -1.0, r2 = -1.0;
double k;
k = CrossRate(p1, p2, np->point[np->points-1], np->point[0]);
if (0 < k && k < 1) {
r1 = k;
}
for (int j = 0; j < np->points-1; ++j) {
p1outside |= IsOutside(p1, np->point[j], np->point[j+1]);
p2outside |= IsOutside(p2, np->point[j], np->point[j+1]);
p3outside |= IsOutside(p3, np->point[j], np->point[j+1]);
k = CrossRate(p1, p2, np->point[j], np->point[j+1]);
if (0 < k && k < 1) {
if (r1 < 0 || k < r1) {
r2 = r1;
r1 = k;
} else if (r2 < 0 || k < r2) {
r2 = k;
}
}
}
PointID pa = -1, pb = -1;
if (p3outside == FALSE) {
if (r1 < 0 || rate < r1) {
r2 = r1;
r1 = rate;
pa = p3;
} else if (r2 < 0 || rate < r2) {
r2 = rate;
pb = p3;
} else {
RemovePoint(p3);
}
} else if (p3 >= 0) {
RemovePoint(p3);
}
if (r1 >= 0 && pa < 0) {
pa = AddPoint(point[p1].x + xd * r1, point[p1].y + yd * r1, point[p1].z + zd * r1);
}
if (r2 >= 0 && pb < 0) {
pb = AddPoint(point[p1].x + xd * r2, point[p1].y + yd * r2, point[p1].z + zd * r2);
}
if (pb >= 0) {
line[i].p2 = pa;
AddLine(pb, p2, line[i].id);
} else if (!p1outside && !p2outside) {
line[i].p1 = line[i].p2 = -1;
} else if (pa >= 0) {
if (!p1outside && p2outside) {
line[i].p1 = pa;
} else if (p1outside && !p2outside) {
line[i].p2 = pa;
}
}
}
}