📄 utils.cpp
字号:
if(loc && old_v != new_v) {
Undo.ValInt(par, loc, flags);
*loc = new_v; return (flags | UNDO_CONTINUE);
}
return flags;
}
DWORD CheckNewDword(DWORD *loc, DWORD old_v, DWORD new_v, GraphObj *par, DWORD flags)
{
if(loc && old_v != new_v) {
Undo.ValDword(par, loc, flags);
*loc = new_v; return (flags | UNDO_CONTINUE);
}
return flags;
}
DWORD CheckNewLFPoint(lfPOINT *loc, lfPOINT *old_v, lfPOINT *new_v, GraphObj *par, DWORD flags)
{
if(loc && old_v && new_v && (old_v->fx != new_v->fx || old_v->fy != new_v->fy)) {
Undo.SaveLFP(par, loc, flags);
loc->fx = new_v->fx; loc->fy = new_v->fy; return (flags | UNDO_CONTINUE);
}
return flags;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//execute clipping of 3D objects
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef struct { //structure required by 3D Bresenhan's algorithm
int d, a, s, *r, l;
}moveDEF;
long sph_r2;
int sph_x, sph_y, sph_z, nclp_pg, seg_x_seg;
POINT3D *clp_pg, *sphlim1, *sphlim2;
double *vclp_pg = 0L;
int test_sphere(int x, int y, int z)
{
int d;
long ld;
ld = (d = x-sph_x) * d; ld += (d = y-sph_y) * d;
ld += (d = z-sph_z) * d;
return (ld > sph_r2) ? 1 : 0;
}
//use a 3D Bresenham alorithm to find z coordinates where x == lx or y == ly
bool line3D_z(POINT3D *p1, POINT3D *p2, int lx, int ly, int *cx, int *cy, int *cz)
{
moveDEF mx, my, mz, *m1, *m2, *m3;
int x, y, z, d1, d2;
mx.d = p2->x - p1->x; mx.a = mx.d >= 0 ? mx.d : -mx.d;
mx.s = mx.d >= 0 ? 1 : -1; mx.r = &x; mx.l = p2->x; x = p1->x;
my.d = p2->y - p1->y; my.a = my.d >= 0 ? my.d : -my.d;
my.s = my.d >= 0 ? 1 : -1; my.r = &y; my.l = p2->y; y = p1->y;
mz.d = p2->z - p1->z; mz.a = mz.d >= 0 ? mz.d : -mz.d;
mz.s = mz.d >= 0 ? 1 : -1; mz.r = &z; mz.l = p2->z; z = p1->z;
if(mx.a > my.a) {
if(mz.a > mx.a) {
m1 = &mz; m2 = &mx; m3 = &my;
}
else if(mz.a > my.a) {
m1 = &mx; m2 = &mz; m3 = &my;
}
else {
m1 = &mx; m2 = &my; m3 = &mz;
}
}
else {
if(mz.a > my.a) {
m1 = &mz; m2 = &my; m3 = &mx;
}
else if(mz.a > mx.a) {
m1 = &my; m2 = &mz; m3 = &mx;
}
else {
m1 = &my; m2 = &mx; m3 = &mz;
}
}
d1 = m2->a - (m1->a >>1); d2 = m3->a - (m1->a >>1);
for(; ;) {
//process point at (m1.r, m2.r, m3.r);
if(x == lx || y == ly) {
*cx = x; *cy = y; *cz = z;
return true;
}
if(*(m1->r) == m1->l) return false;
if(d1 >= 0) {
*(m2->r) += m2->s; d1 -= m1->a;
}
if(d2 >= 0) {
*(m3->r) += m3->s; d2 -= m1->a;
}
*(m1->r) += m1->s; d1 += m2->a; d2 += m3->a;
}
}
//test if point is 1) outside, 2) above, 3) on the line, or 0) hidden by a plane
int test_plane(int x, int y, int z)
{
int us, ls, us1, ls1, x1, y1, z1, x2, y2, z2;
static int last = 0;
POINT3D p1, p2;
if(IsInPolygon3D(x, y, clp_pg, nclp_pg, &us, &ls)) {
if(us == ls){
seg_x_seg = us;
return last = 3; //point is on line: visible
}
if(vclp_pg) {
if(iround((x * vclp_pg[0] + y * vclp_pg[1] - vclp_pg[3])/vclp_pg[2]) < z)
return last = 2;
else return last = 0;
}
if(us < 1) us1 = nclp_pg -1; else us1 = us -1;
if(ls < 1) ls1 = nclp_pg -1; else ls1 = ls -1;
if(z < clp_pg[us1].z && z < clp_pg[us].z && z < clp_pg[ls1].z &&
z < clp_pg[ls].z) return last = 0; //far below plane
if(z > clp_pg[us1].z && z > clp_pg[us].z && z > clp_pg[ls1].z &&
z > clp_pg[ls].z) return last = 2; //far above plane
if(line3D_z(&clp_pg[us1], &clp_pg[us], x, -1, &x1, &y1, &z1) &&
line3D_z(&clp_pg[ls1], &clp_pg[ls], x, -1, &x2, &y2, &z2)){
if(z1 < z && z2 < z) return last = 2;
if(z1 >= z && z2 >= z) return last = 0;
p1.x = x1; p1.y = y1; p1.z = z1; p2.x = x2; p2.y = y2; p2.z = z2;
if(line3D_z(&p1, &p2, -1, y, &x1, &y1, &z1)) {
if(z > z1) return last = 2;
else return last = 0;
}
}
return last;
}
return last = 1;
}
int test_planeandline(int x, int y, int z)
{
int ret;
ret = test_plane(x, y, z);
if(ret == 3 && clp_pg && nclp_pg && idx_point_on_line < nclp_pg) {
if(vclp_pg) {
if(iround((x * vclp_pg[0] + y * vclp_pg[1] - vclp_pg[3])/vclp_pg[2]) < z)
return 2;
else return 0;
}
else {
// no equation for plane available
}
}
return ret;
}
void proc_polygon(int vis, POINT3D *pnt, POINT3D * last); //prototype
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//use a 3D Bresenham algorithm to clip lines
void clip_line_3D(GraphObj *go, POINT3D *p1, POINT3D *p2, int(*proc)(int, int, int))
{
moveDEF mx, my, mz, *m1, *m2, *m3;
int x, y, z, d1, d2, vis;
bool bVisible, bDrawLater = false;
POINT3D p, lp;
if(p1->x == p2->x && p1->y == p2->y && p1->z == p2->z) return;
mx.d = p2->x - p1->x; mx.a = mx.d >= 0 ? mx.d : -mx.d;
mx.s = mx.d >= 0 ? 1 : -1; mx.r = &x; mx.l = p2->x; x = p1->x;
my.d = p2->y - p1->y; my.a = my.d >= 0 ? my.d : -my.d;
my.s = my.d >= 0 ? 1 : -1; my.r = &y; my.l = p2->y; y = p1->y;
mz.d = p2->z - p1->z; mz.a = mz.d >= 0 ? mz.d : -mz.d;
mz.s = mz.d >= 0 ? 1 : -1; mz.r = &z; mz.l = p2->z; z = p1->z;
if(mx.a > my.a) {
if(mz.a > mx.a) {
m1 = &mz; m2 = &mx; m3 = &my;
}
else if(mz.a > my.a) {
m1 = &mx; m2 = &mz; m3 = &my;
}
else {
m1 = &mx; m2 = &my; m3 = &mz;
}
}
else {
if(mz.a > my.a) {
m1 = &mz; m2 = &my; m3 = &mx;
}
else if(mz.a > mx.a) {
m1 = &my; m2 = &mz; m3 = &mx;
}
else {
m1 = &my; m2 = &mx; m3 = &mz;
}
}
bVisible = (0 != (vis = (*proc)(x, y, z)));
if((bDrawLater = (vis == 2)) && go) go->Command(CMD_DRAW_LATER, 0L, 0L);
lp.x = p1->x; lp.y = p1->y; lp.z = p1->z;
if(!go && vis) proc_polygon(vis, p1, p1);
d1 = m2->a - (m1->a >>1); d2 = m3->a - (m1->a >>1);
for(; ;) {
//process point at (m1.r, m2.r, m3.r);
vis = (*proc)(x, y, z);
if(!bDrawLater && vis == 2){
if(go) go->Command(CMD_DRAW_LATER, 0L, 0L);
bDrawLater = true;
}
if(bVisible) {
if(!vis) {
p.x = x; p.y = y; p.z = z;
if(go) go->Command(CMD_ADDTOLINE, &lp, 0L);
else proc_polygon(vis, &p, &lp);
bVisible = false;
}
}
else if(vis){
p.x = x; p.y = y; p.z = z;
if(go) go->Command(CMD_STARTLINE, &p, 0L);
else proc_polygon(vis, &p, &lp);
bVisible = true;
}
if(*(m1->r) == m1->l){
if(vis){
p.x = x; p.y = y; p.z = z;
if(go) go->Command(CMD_ADDTOLINE, &p, 0L);
else proc_polygon(vis, &p, &lp);
}
return;
}
lp.x = x; lp.y = y; lp.z = z;
if(d1 >= 0) {
*(m2->r) += m2->s; d1 -= m1->a;
}
if(d2 >= 0) {
*(m3->r) += m3->s; d2 -= m1->a;
}
*(m1->r) += m1->s; d1 += m2->a; d2 += m3->a;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//use circular Bresenham's algorithm to clip a spherical scanline
//Ref: C. Montani, R. Scopigno (1990) "Speres-To-Voxel Conversion", in:
// Graphic Gems (A.S. Glassner ed.) Academic Press, Inc.;
// ISBN 0-12-288165-5
void clip_spher_line(GraphObj *go, POINT3D *cent, int r, bool bVert, int(*proc)(int, int, int))
{
int x, y, q, di, de, lim;
int vis = 0, o_vis;
POINT3D cpos;
if(r < 1) return;
cpos.x = cent->x; cpos.y = cent->y; cpos.z = cent->z;
if(bVert) cpos.y -= r;
else cpos.x -= r;
for(q = 0; q < 2; q++) {
x = lim = 0; y = r; di = 2*(1-r);
while (y >= lim){
o_vis = vis;
if(bVert && (cpos.x < sphlim1->x || cpos.x > sphlim2->x)) vis = 0;
else if (cpos.y < sphlim1->y || cpos.y > sphlim2->y) vis = 0;
else if (cpos.x > 0 && cpos.y >0) vis = (*proc)(cpos.x, cpos.y, cpos.z);
if(vis != o_vis) {
if(vis) go->Command(CMD_STARTLINE, &cpos, 0L);
else go->Command(CMD_ADDTOLINE, &cpos, 0L);
}
if(di < 0) {
de = 2*di + 2*y -1;
if(de > 0) {
x++; y--; di += (2*x -2*y +2);
}
else {
x++; di += (2*x +1);
}
}
else {
de = 2*di -2*x -1;
if(de > 0) {
y--; di += (-2*y +1);
}
else {
x++; y--; di += (2*x -2*y +2);
}
}
switch(q) {
case 0:
if(bVert) cpos.y = cent->y - y;
else cpos.x = cent->x - y;
cpos.z = cent->z + x;
break;
case 1:
if(vis && y < lim) go->Command(CMD_ADDTOLINE, &cpos, 0L);
if(bVert) cpos.y = cent->y + x;
else cpos.x = cent->x + x;
cpos.z = cent->z + y;
break;
}
}
}
return;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//come here to process polygon clipping events
int ppg_vis, ppg_level, ppg_reason, ppg_firstvis, ppg_nact, ppg_nmask;
bool ppg_nowvis;
POINT *ppg_mask;
POINT3D ppg_first, *ppg_act;
GraphObj *ppg_par;
double *ppg_vec = 0L;
// test if point is on line of 3D polygon
//Ref: P.S. Heckbert (1990) "Digital Line Drawing", in: Graphic Gems
// (A.S. Glassner, ed.); Academic Press, Inc.,
// ISBN 0-12-286165-5
// void AddToPolygon(long *cp, POINT *pts, POINT *np);
bool IsOnLine(POINT *p1, POINT *p2, int x, int y)
{
int d, ax, ay, sx, sy, dx, dy;
POINT tr;
dx = p2->x - p1->x;
if ( p2->x < p1->x) { ax = (-dx)<<1; sx = -1; }
else { ax = dx <<1; sx = 1; }
dy = p2->y - p1->y;
if (p2->y < p1->y) { ay = (-dy)<<1; sy = -1; }
else { ay = dy<<1; sy = 1; }
tr.x = p1->x; tr.y = p1->y;
if (ax > ay) { // x dominant
d = ay - (ax >>1);
for ( ; ; ) {
if(tr.y == y && tr.x == x) return true; //match
if(tr.x == p2->x) return false;
if (d >= 0) {tr.y += sy; d -= ax;}
tr.x += sx; d += ay;
}
}
else { // y dominant
d = ax - (ay >>1);
for ( ; ; ) {
if(tr.x == x && tr.y == y) return true; //match
if (tr.y == p2->y) return false;
if (d >= 0) {tr.x += sx; d -= ay;}
tr.y += sy; d += ax;
}
}
}
//use Bresenham's algorithm to complete a partially hidden polygon
// by the shadow of the above surface
//Ref: P.S. Heckbert (1990) "Digital Line Drawing", in: Graphic Gems
// (A.S. Glassner, ed.); Academic Press, Inc.,
// ISBN 0-12-286165-5
// void AddToPolygon(long *cp, POINT *pts, POINT *np);
bool ShadowPolygon(POINT *p1, POINT *p2, POINT *tp, int ntp, POINT *pts, long *cp, POINT *lim)
{
int d, ax, ay, sx, sy, dx, dy;
bool bPen, vis;
POINT tr, mp;
long d1, ndist, dist = 99999;
dx = p2->x - p1->x;
if ( p2->x < p1->x) { ax = (-dx)<<1; sx = -1; }
else { ax = dx <<1; sx = 1; }
dy = p2->y - p1->y;
if (p2->y < p1->y) { ay = (-dy)<<1; sy = -1; }
else { ay = dy<<1; sy = 1; }
tr.x = p1->x; tr.y = p1->y;
bPen = IsInPolygon(&tr, tp, ntp) || IsCloseToPL(tr, tp, ntp);
AddToPolygon(cp, pts, p1); //first Point is always visible
if (ax > ay) { // x dominant
d = ay - (ax >>1);
for ( ; ; ) {
if(abs(tr.y - lim->y) < 3 && abs(tr.x - lim->x) < 3) {
ndist = (d1=(tr.y - lim->y))*d1;
ndist += ((d1=(tr.x - lim->x))*d1);
if(ndist <= dist) {
mp.x = tr.x; mp.y = tr.y; dist = ndist;
}
else {
//mp is the closest point
AddToPolygon(cp, pts, &mp);
return false;
}
}
vis = IsInPolygon(&tr, tp, ntp) || IsCloseToPL(tr, tp, ntp);
if(bPen && !vis) {
AddToPolygon(cp, pts, &tr);
return false; //now leaving the polygon
}
if(tr.x == p2->x) return true; //still inside
if (d >= 0) {tr.y += sy; d -= ax;}
bPen = vis; tr.x += sx; d += ay;
}
}
else { // y dominant
d = ax - (ay >>1);
for ( ; ; ) {
if(abs(tr.x - lim->x) < 3 && abs(tr.y - lim->y) < 3) {
ndist = (d1=(tr.y - lim->y))*d1;
ndist += ((d1=(tr.x - lim->x))*d1);
if(ndist <= dist) {
mp.x = tr.x; mp.y = tr.y; dist = ndist;
}
else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -