699 lines
19 KiB
C++
699 lines
19 KiB
C++
|
// File: crn_arealist.cpp - 2D shape algebra (currently unused)
|
||
|
// See Copyright Notice and license at the end of inc/crnlib.h
|
||
|
// Ported from the PowerView DOS image viewer, a product I wrote back in 1993. Not currently used in the open source release of crnlib.
|
||
|
#include "crn_core.h"
|
||
|
#include "crn_arealist.h"
|
||
|
|
||
|
#define RECT_DEBUG
|
||
|
|
||
|
namespace crnlib
|
||
|
{
|
||
|
|
||
|
static void area_fatal_error(const char* pFunc, const char* pMsg, ...)
|
||
|
{
|
||
|
pFunc;
|
||
|
va_list args;
|
||
|
va_start(args, pMsg);
|
||
|
|
||
|
char buf[512];
|
||
|
#ifdef _MSC_VER
|
||
|
_vsnprintf_s(buf, sizeof(buf), pMsg, args);
|
||
|
#else
|
||
|
vsnprintf(buf, sizeof(buf), pMsg, args);
|
||
|
#endif
|
||
|
|
||
|
va_end(args);
|
||
|
|
||
|
CRNLIB_FAIL(buf);
|
||
|
}
|
||
|
|
||
|
static Area * delete_area(Area_List *Plist, Area *Parea)
|
||
|
{
|
||
|
Area *p, *q;
|
||
|
|
||
|
#ifdef RECT_DEBUG
|
||
|
if ((Parea == Plist->Phead) || (Parea == Plist->Ptail))
|
||
|
area_fatal_error("delete_area", "tried to remove head or tail");
|
||
|
#endif
|
||
|
|
||
|
p = Parea->Pprev;
|
||
|
q = Parea->Pnext;
|
||
|
p->Pnext = q;
|
||
|
q->Pprev = p;
|
||
|
|
||
|
Parea->Pnext = Plist->Pfree;
|
||
|
Parea->Pprev = NULL;
|
||
|
Plist->Pfree = Parea;
|
||
|
|
||
|
return (q);
|
||
|
}
|
||
|
|
||
|
static Area * alloc_area(Area_List *Plist)
|
||
|
{
|
||
|
Area *p = Plist->Pfree;
|
||
|
|
||
|
if (p == NULL)
|
||
|
{
|
||
|
if (Plist->next_free == Plist->total_areas)
|
||
|
area_fatal_error("alloc_area", "Out of areas!");
|
||
|
|
||
|
p = Plist->Phead + Plist->next_free;
|
||
|
Plist->next_free++;
|
||
|
}
|
||
|
else
|
||
|
Plist->Pfree = p->Pnext;
|
||
|
|
||
|
return (p);
|
||
|
}
|
||
|
|
||
|
static Area * insert_area_before(Area_List *Plist, Area *Parea,
|
||
|
int x1, int y1, int x2, int y2)
|
||
|
{
|
||
|
Area *p, *Pnew_area = alloc_area(Plist);
|
||
|
|
||
|
p = Parea->Pprev;
|
||
|
|
||
|
p->Pnext = Pnew_area;
|
||
|
|
||
|
Pnew_area->Pprev = p;
|
||
|
Pnew_area->Pnext = Parea;
|
||
|
|
||
|
Parea->Pprev = Pnew_area;
|
||
|
|
||
|
Pnew_area->x1 = x1;
|
||
|
Pnew_area->y1 = y1;
|
||
|
Pnew_area->x2 = x2;
|
||
|
Pnew_area->y2 = y2;
|
||
|
|
||
|
return (Pnew_area);
|
||
|
}
|
||
|
|
||
|
static Area * insert_area_after(Area_List *Plist, Area *Parea,
|
||
|
int x1, int y1, int x2, int y2)
|
||
|
{
|
||
|
Area *p, *Pnew_area = alloc_area(Plist);
|
||
|
|
||
|
p = Parea->Pnext;
|
||
|
|
||
|
p->Pprev = Pnew_area;
|
||
|
|
||
|
Pnew_area->Pnext = p;
|
||
|
Pnew_area->Pprev = Parea;
|
||
|
|
||
|
Parea->Pnext = Pnew_area;
|
||
|
|
||
|
Pnew_area->x1 = x1;
|
||
|
Pnew_area->y1 = y1;
|
||
|
Pnew_area->x2 = x2;
|
||
|
Pnew_area->y2 = y2;
|
||
|
|
||
|
return (Pnew_area);
|
||
|
}
|
||
|
|
||
|
void Area_List_deinit(Area_List* Pobj_base)
|
||
|
{
|
||
|
Area_List *Plist = (Area_List *)Pobj_base;
|
||
|
|
||
|
if (!Plist)
|
||
|
return;
|
||
|
|
||
|
if (Plist->Phead)
|
||
|
{
|
||
|
crnlib_free(Plist->Phead);
|
||
|
Plist->Phead = NULL;
|
||
|
}
|
||
|
|
||
|
crnlib_free(Plist);
|
||
|
}
|
||
|
|
||
|
Area_List * Area_List_init(int max_areas)
|
||
|
{
|
||
|
Area_List *Plist = (Area_List*)crnlib_calloc(1, sizeof(Area_List));
|
||
|
|
||
|
Plist->total_areas = max_areas + 2;
|
||
|
|
||
|
Plist->Phead = (Area *)crnlib_calloc(max_areas + 2, sizeof(Area));
|
||
|
Plist->Ptail = Plist->Phead + 1;
|
||
|
|
||
|
Plist->Phead->Pprev = NULL;
|
||
|
Plist->Phead->Pnext = Plist->Ptail;
|
||
|
|
||
|
Plist->Ptail->Pprev = Plist->Phead;
|
||
|
Plist->Ptail->Pnext = NULL;
|
||
|
|
||
|
Plist->Pfree = NULL;
|
||
|
Plist->next_free = 2;
|
||
|
|
||
|
return (Plist);
|
||
|
}
|
||
|
|
||
|
void Area_List_print(Area_List *Plist)
|
||
|
{
|
||
|
Area *Parea = Plist->Phead->Pnext;
|
||
|
|
||
|
while (Parea != Plist->Ptail)
|
||
|
{
|
||
|
printf("%04i %04i : %04i %04i\n", Parea->x1, Parea->y1, Parea->x2, Parea->y2);
|
||
|
|
||
|
Parea = Parea->Pnext;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Area_List * Area_List_dup_new(Area_List *Plist,
|
||
|
int x_ofs, int y_ofs)
|
||
|
{
|
||
|
int i;
|
||
|
Area_List *Pnew_list = (Area_List*)crnlib_calloc(1, sizeof(Area_List));
|
||
|
|
||
|
Pnew_list->total_areas = Plist->total_areas;
|
||
|
|
||
|
Pnew_list->Phead = (Area *)crnlib_malloc(sizeof(Area) * Plist->total_areas);
|
||
|
Pnew_list->Ptail = Pnew_list->Phead + 1;
|
||
|
|
||
|
Pnew_list->Pfree = (Plist->Pfree) ? ((Plist->Pfree - Plist->Phead) + Pnew_list->Phead) : NULL;
|
||
|
|
||
|
Pnew_list->next_free = Plist->next_free;
|
||
|
|
||
|
memcpy(Pnew_list->Phead, Plist->Phead, sizeof(Area) * Plist->total_areas);
|
||
|
|
||
|
for (i = 0; i < Plist->total_areas; i++)
|
||
|
{
|
||
|
Pnew_list->Phead[i].Pnext = (Plist->Phead[i].Pnext == NULL) ? NULL : (Plist->Phead[i].Pnext - Plist->Phead) + Pnew_list->Phead;
|
||
|
Pnew_list->Phead[i].Pprev = (Plist->Phead[i].Pprev == NULL) ? NULL : (Plist->Phead[i].Pprev - Plist->Phead) + Pnew_list->Phead;
|
||
|
|
||
|
Pnew_list->Phead[i].x1 += x_ofs;
|
||
|
Pnew_list->Phead[i].y1 += y_ofs;
|
||
|
Pnew_list->Phead[i].x2 += x_ofs;
|
||
|
Pnew_list->Phead[i].y2 += y_ofs;
|
||
|
}
|
||
|
|
||
|
return (Pnew_list);
|
||
|
}
|
||
|
|
||
|
uint Area_List_get_num(Area_List* Plist)
|
||
|
{
|
||
|
uint num = 0;
|
||
|
|
||
|
Area *Parea = Plist->Phead->Pnext;
|
||
|
|
||
|
while (Parea != Plist->Ptail)
|
||
|
{
|
||
|
num++;
|
||
|
|
||
|
Parea = Parea->Pnext;
|
||
|
}
|
||
|
|
||
|
return num;
|
||
|
}
|
||
|
|
||
|
void Area_List_dup(Area_List *Psrc_list, Area_List *Pdst_list,
|
||
|
int x_ofs, int y_ofs)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if (Psrc_list->total_areas != Pdst_list->total_areas)
|
||
|
area_fatal_error("Area_List_dup", "Src and Dst total_areas must be equal!");
|
||
|
|
||
|
Pdst_list->Pfree = (Psrc_list->Pfree) ? ((Psrc_list->Pfree - Psrc_list->Phead) + Pdst_list->Phead) : NULL;
|
||
|
|
||
|
Pdst_list->next_free = Psrc_list->next_free;
|
||
|
|
||
|
memcpy(Pdst_list->Phead, Psrc_list->Phead, sizeof(Area) * Psrc_list->total_areas);
|
||
|
|
||
|
if ((x_ofs) || (y_ofs))
|
||
|
{
|
||
|
for (i = 0; i < Psrc_list->total_areas; i++)
|
||
|
{
|
||
|
Pdst_list->Phead[i].Pnext = (Psrc_list->Phead[i].Pnext == NULL) ? NULL : (Psrc_list->Phead[i].Pnext - Psrc_list->Phead) + Pdst_list->Phead;
|
||
|
Pdst_list->Phead[i].Pprev = (Psrc_list->Phead[i].Pprev == NULL) ? NULL : (Psrc_list->Phead[i].Pprev - Psrc_list->Phead) + Pdst_list->Phead;
|
||
|
|
||
|
Pdst_list->Phead[i].x1 += x_ofs;
|
||
|
Pdst_list->Phead[i].y1 += y_ofs;
|
||
|
Pdst_list->Phead[i].x2 += x_ofs;
|
||
|
Pdst_list->Phead[i].y2 += y_ofs;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (i = 0; i < Psrc_list->total_areas; i++)
|
||
|
{
|
||
|
Pdst_list->Phead[i].Pnext = (Psrc_list->Phead[i].Pnext == NULL) ? NULL : (Psrc_list->Phead[i].Pnext - Psrc_list->Phead) + Pdst_list->Phead;
|
||
|
Pdst_list->Phead[i].Pprev = (Psrc_list->Phead[i].Pprev == NULL) ? NULL : (Psrc_list->Phead[i].Pprev - Psrc_list->Phead) + Pdst_list->Phead;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Area_List_copy(
|
||
|
Area_List *Psrc_list, Area_List *Pdst_list,
|
||
|
int x_ofs, int y_ofs)
|
||
|
{
|
||
|
Area *Parea = Psrc_list->Phead->Pnext;
|
||
|
|
||
|
Area_List_clear(Pdst_list);
|
||
|
|
||
|
if ((x_ofs) || (y_ofs))
|
||
|
{
|
||
|
Area *Pprev_area = Pdst_list->Phead;
|
||
|
|
||
|
while (Parea != Psrc_list->Ptail)
|
||
|
{
|
||
|
// Area *p, *Pnew_area;
|
||
|
Area *Pnew_area;
|
||
|
|
||
|
if (Pdst_list->next_free == Pdst_list->total_areas)
|
||
|
area_fatal_error("Area_List_copy", "Out of areas!");
|
||
|
|
||
|
Pnew_area = Pdst_list->Phead + Pdst_list->next_free;
|
||
|
Pdst_list->next_free++;
|
||
|
|
||
|
Pnew_area->Pprev = Pprev_area;
|
||
|
Pprev_area->Pnext = Pnew_area;
|
||
|
|
||
|
Pnew_area->x1 = Parea->x1 + x_ofs;
|
||
|
Pnew_area->y1 = Parea->y1 + y_ofs;
|
||
|
Pnew_area->x2 = Parea->x2 + x_ofs;
|
||
|
Pnew_area->y2 = Parea->y2 + y_ofs;
|
||
|
|
||
|
Pprev_area = Pnew_area;
|
||
|
|
||
|
Parea = Parea->Pnext;
|
||
|
}
|
||
|
|
||
|
Pprev_area->Pnext = Pdst_list->Ptail;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#if 0
|
||
|
while (Parea != Psrc_list->Ptail)
|
||
|
{
|
||
|
insert_area_after(Pdst_list, Pdst_list->Phead,
|
||
|
Parea->x1,
|
||
|
Parea->y1,
|
||
|
Parea->x2,
|
||
|
Parea->y2);
|
||
|
|
||
|
Parea = Parea->Pnext;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
Area *Pprev_area = Pdst_list->Phead;
|
||
|
|
||
|
while (Parea != Psrc_list->Ptail)
|
||
|
{
|
||
|
// Area *p, *Pnew_area;
|
||
|
Area *Pnew_area;
|
||
|
|
||
|
if (Pdst_list->next_free == Pdst_list->total_areas)
|
||
|
area_fatal_error("Area_List_copy", "Out of areas!");
|
||
|
|
||
|
Pnew_area = Pdst_list->Phead + Pdst_list->next_free;
|
||
|
Pdst_list->next_free++;
|
||
|
|
||
|
Pnew_area->Pprev = Pprev_area;
|
||
|
Pprev_area->Pnext = Pnew_area;
|
||
|
|
||
|
Pnew_area->x1 = Parea->x1;
|
||
|
Pnew_area->y1 = Parea->y1;
|
||
|
Pnew_area->x2 = Parea->x2;
|
||
|
Pnew_area->y2 = Parea->y2;
|
||
|
|
||
|
Pprev_area = Pnew_area;
|
||
|
|
||
|
Parea = Parea->Pnext;
|
||
|
}
|
||
|
|
||
|
Pprev_area->Pnext = Pdst_list->Ptail;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Area_List_clear(Area_List *Plist)
|
||
|
{
|
||
|
Plist->Phead->Pnext = Plist->Ptail;
|
||
|
Plist->Ptail->Pprev = Plist->Phead;
|
||
|
Plist->Pfree = NULL;
|
||
|
Plist->next_free = 2;
|
||
|
}
|
||
|
|
||
|
void Area_List_set(Area_List *Plist, int x1, int y1, int x2, int y2)
|
||
|
{
|
||
|
Plist->Pfree = NULL;
|
||
|
|
||
|
Plist->Phead[2].x1 = x1;
|
||
|
Plist->Phead[2].y1 = y1;
|
||
|
Plist->Phead[2].x2 = x2;
|
||
|
Plist->Phead[2].y2 = y2;
|
||
|
|
||
|
Plist->Phead[2].Pprev = Plist->Phead;
|
||
|
Plist->Phead->Pnext = Plist->Phead + 2;
|
||
|
|
||
|
Plist->Phead[2].Pnext = Plist->Ptail;
|
||
|
Plist->Ptail->Pprev = Plist->Phead + 2;
|
||
|
|
||
|
Plist->next_free = 3;
|
||
|
}
|
||
|
|
||
|
void Area_List_remove(Area_List *Plist,
|
||
|
int x1, int y1, int x2, int y2)
|
||
|
{
|
||
|
int l, h;
|
||
|
Area *Parea = Plist->Phead->Pnext;
|
||
|
|
||
|
#ifdef RECT_DEBUG
|
||
|
if ((x1 > x2) || (y1 > y2))
|
||
|
area_fatal_error("area_list_remove", "invalid coords: %i %i %i %i", x1, y1, x2, y2);
|
||
|
#endif
|
||
|
|
||
|
while (Parea != Plist->Ptail)
|
||
|
{
|
||
|
// Not touching
|
||
|
if ((x2 < Parea->x1) || (x1 > Parea->x2) ||
|
||
|
(y2 < Parea->y1) || (y1 > Parea->y2))
|
||
|
{
|
||
|
Parea = Parea->Pnext;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Completely covers
|
||
|
if ((x1 <= Parea->x1) && (x2 >= Parea->x2) &&
|
||
|
(y1 <= Parea->y1) && (y2 >= Parea->y2))
|
||
|
{
|
||
|
if ((x1 == Parea->x1) && (x2 == Parea->x2) &&
|
||
|
(y1 == Parea->y1) && (y2 == Parea->y2))
|
||
|
{
|
||
|
delete_area(Plist, Parea);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Parea = delete_area(Plist, Parea);
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// top
|
||
|
if (y1 > Parea->y1)
|
||
|
{
|
||
|
insert_area_before(Plist, Parea,
|
||
|
Parea->x1, Parea->y1,
|
||
|
Parea->x2, y1 - 1);
|
||
|
}
|
||
|
|
||
|
// bottom
|
||
|
if (y2 < Parea->y2)
|
||
|
{
|
||
|
insert_area_before(Plist, Parea,
|
||
|
Parea->x1, y2 + 1,
|
||
|
Parea->x2, Parea->y2);
|
||
|
}
|
||
|
|
||
|
l = math::maximum(y1, Parea->y1);
|
||
|
h = math::minimum(y2, Parea->y2);
|
||
|
|
||
|
// left middle
|
||
|
if (x1 > Parea->x1)
|
||
|
{
|
||
|
insert_area_before(Plist, Parea,
|
||
|
Parea->x1, l,
|
||
|
x1 - 1, h);
|
||
|
}
|
||
|
|
||
|
// right middle
|
||
|
if (x2 < Parea->x2)
|
||
|
{
|
||
|
insert_area_before(Plist, Parea,
|
||
|
x2 + 1, l,
|
||
|
Parea->x2, h);
|
||
|
}
|
||
|
|
||
|
// early out - we know there's nothing else to remove, as areas can
|
||
|
// never overlap
|
||
|
if ((x1 >= Parea->x1) && (x2 <= Parea->x2) &&
|
||
|
(y1 >= Parea->y1) && (y2 <= Parea->y2))
|
||
|
{
|
||
|
delete_area(Plist, Parea);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Parea = delete_area(Plist, Parea);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Area_List_insert(Area_List *Plist,
|
||
|
int x1, int y1, int x2, int y2,
|
||
|
bool combine)
|
||
|
{
|
||
|
Area *Parea = Plist->Phead->Pnext;
|
||
|
|
||
|
#ifdef RECT_DEBUG
|
||
|
if ((x1 > x2) || (y1 > y2))
|
||
|
area_fatal_error("Area_List_insert", "invalid coords: %i %i %i %i", x1, y1, x2, y2);
|
||
|
#endif
|
||
|
|
||
|
while (Parea != Plist->Ptail)
|
||
|
{
|
||
|
// totally covers
|
||
|
if ((x1 <= Parea->x1) && (x2 >= Parea->x2) &&
|
||
|
(y1 <= Parea->y1) && (y2 >= Parea->y2))
|
||
|
{
|
||
|
Parea = delete_area(Plist, Parea);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// intersects
|
||
|
if ((x2 >= Parea->x1) && (x1 <= Parea->x2) &&
|
||
|
(y2 >= Parea->y1) && (y1 <= Parea->y2))
|
||
|
{
|
||
|
int ax1, ay1, ax2, ay2;
|
||
|
|
||
|
ax1 = Parea->x1;
|
||
|
ay1 = Parea->y1;
|
||
|
ax2 = Parea->x2;
|
||
|
ay2 = Parea->y2;
|
||
|
|
||
|
if (x1 < ax1)
|
||
|
Area_List_insert(Plist, x1, math::maximum(y1, ay1), ax1 - 1, math::minimum(y2, ay2), combine);
|
||
|
|
||
|
if (x2 > ax2)
|
||
|
Area_List_insert(Plist, ax2 + 1, math::maximum(y1, ay1), x2, math::minimum(y2, ay2), combine);
|
||
|
|
||
|
if (y1 < ay1)
|
||
|
Area_List_insert(Plist, x1, y1, x2, ay1 - 1, combine);
|
||
|
|
||
|
if (y2 > ay2)
|
||
|
Area_List_insert(Plist, x1, ay2 + 1, x2, y2, combine);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (combine)
|
||
|
{
|
||
|
if ((x1 == Parea->x1) && (x2 == Parea->x2))
|
||
|
{
|
||
|
if ((y2 == Parea->y1 - 1) || (y1 == Parea->y2 + 1))
|
||
|
{
|
||
|
delete_area(Plist, Parea);
|
||
|
Area_List_insert(Plist, x1, math::minimum(y1, Parea->y1), x2, math::maximum(y2, Parea->y2), CRNLIB_TRUE);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else if ((y1 == Parea->y1) && (y2 == Parea->y2))
|
||
|
{
|
||
|
if ((x2 == Parea->x1 - 1) || (x1 == Parea->x2 + 1))
|
||
|
{
|
||
|
delete_area(Plist, Parea);
|
||
|
Area_List_insert(Plist, math::minimum(x1, Parea->x1), y1, math::maximum(x2, Parea->x2), y2, CRNLIB_TRUE);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Parea = Parea->Pnext;
|
||
|
}
|
||
|
|
||
|
insert_area_before(Plist, Parea, x1, y1, x2, y2);
|
||
|
}
|
||
|
|
||
|
void Area_List_intersect_area(Area_List *Plist,
|
||
|
int x1, int y1, int x2, int y2)
|
||
|
{
|
||
|
Area *Parea = Plist->Phead->Pnext;
|
||
|
|
||
|
while (Parea != Plist->Ptail)
|
||
|
{
|
||
|
// doesn't cover
|
||
|
if ((x2 < Parea->x1) || (x1 > Parea->x2) ||
|
||
|
(y2 < Parea->y1) || (y1 > Parea->y2))
|
||
|
{
|
||
|
Parea = delete_area(Plist, Parea);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// totally covers
|
||
|
if ((x1 <= Parea->x1) && (x2 >= Parea->x2) &&
|
||
|
(y1 <= Parea->y1) && (y2 >= Parea->y2))
|
||
|
{
|
||
|
Parea = Parea->Pnext;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Oct 21- should insert after, because deleted area will access the NEXT area!
|
||
|
// insert_area_after(Plist, Parea,
|
||
|
// math::maximum(x1, Parea->x1),
|
||
|
// math::maximum(y1, Parea->y1),
|
||
|
// math::minimum(x2, Parea->x2),
|
||
|
// math::minimum(y2, Parea->y2));
|
||
|
|
||
|
insert_area_before(Plist, Parea,
|
||
|
math::maximum(x1, Parea->x1),
|
||
|
math::maximum(y1, Parea->y1),
|
||
|
math::minimum(x2, Parea->x2),
|
||
|
math::minimum(y2, Parea->y2));
|
||
|
|
||
|
Parea = delete_area(Plist, Parea);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
void Area_List_intersect_Area_List(
|
||
|
Area_List *Pouter_list,
|
||
|
Area_List *Pinner_list,
|
||
|
Area_List *Pdst_list)
|
||
|
{
|
||
|
Area *Parea1 = Pouter_list->Phead->Pnext;
|
||
|
|
||
|
while (Parea1 != Pouter_list->Ptail)
|
||
|
{
|
||
|
Area *Parea2 = Pinner_list->Phead->Pnext;
|
||
|
int x1, y1, x2, y2;
|
||
|
|
||
|
x1 = Parea1->x1; x2 = Parea1->x2;
|
||
|
y1 = Parea1->y1; y2 = Parea1->y2;
|
||
|
|
||
|
while (Parea2 != Pinner_list->Ptail)
|
||
|
{
|
||
|
if ((x1 <= Parea2->x2) && (x2 >= Parea2->x1) &&
|
||
|
(y1 <= Parea2->y2) && (y2 >= Parea2->y1))
|
||
|
{
|
||
|
insert_area_after(Pdst_list, Pdst_list->Phead,
|
||
|
math::maximum(x1, Parea2->x1),
|
||
|
math::maximum(y1, Parea2->y1),
|
||
|
math::minimum(x2, Parea2->x2),
|
||
|
math::minimum(y2, Parea2->y2));
|
||
|
}
|
||
|
|
||
|
Parea2 = Parea2->Pnext;
|
||
|
}
|
||
|
|
||
|
Parea1 = Parea1->Pnext;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if 1
|
||
|
void Area_List_intersect_Area_List(Area_List *Pouter_list,
|
||
|
Area_List *Pinner_list,
|
||
|
Area_List *Pdst_list)
|
||
|
{
|
||
|
Area *Parea1 = Pouter_list->Phead->Pnext;
|
||
|
|
||
|
while (Parea1 != Pouter_list->Ptail)
|
||
|
{
|
||
|
Area *Parea2 = Pinner_list->Phead->Pnext;
|
||
|
int x1, y1, x2, y2;
|
||
|
|
||
|
x1 = Parea1->x1; x2 = Parea1->x2;
|
||
|
y1 = Parea1->y1; y2 = Parea1->y2;
|
||
|
|
||
|
while (Parea2 != Pinner_list->Ptail)
|
||
|
{
|
||
|
if ((x1 <= Parea2->x2) && (x2 >= Parea2->x1) &&
|
||
|
(y1 <= Parea2->y2) && (y2 >= Parea2->y1))
|
||
|
{
|
||
|
int nx1, ny1, nx2, ny2;
|
||
|
|
||
|
nx1 = math::maximum(x1, Parea2->x1);
|
||
|
ny1 = math::maximum(y1, Parea2->y1);
|
||
|
nx2 = math::minimum(x2, Parea2->x2);
|
||
|
ny2 = math::minimum(y2, Parea2->y2);
|
||
|
|
||
|
if (Pdst_list->Phead->Pnext == Pdst_list->Ptail)
|
||
|
{
|
||
|
insert_area_after(Pdst_list, Pdst_list->Phead,
|
||
|
nx1, ny1, nx2, ny2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Area_Ptr Ptemp = Pdst_list->Phead->Pnext;
|
||
|
if ((Ptemp->x1 == nx1) && (Ptemp->x2 == nx2))
|
||
|
{
|
||
|
if (Ptemp->y1 == (ny2+1))
|
||
|
{
|
||
|
Ptemp->y1 = ny1;
|
||
|
goto next;
|
||
|
}
|
||
|
else if (Ptemp->y2 == (ny1-1))
|
||
|
{
|
||
|
Ptemp->y2 = ny2;
|
||
|
goto next;
|
||
|
}
|
||
|
}
|
||
|
else if ((Ptemp->y1 == ny1) && (Ptemp->y2 == ny2))
|
||
|
{
|
||
|
if (Ptemp->x1 == (nx2+1))
|
||
|
{
|
||
|
Ptemp->x1 = nx1;
|
||
|
goto next;
|
||
|
}
|
||
|
else if (Ptemp->x2 == (nx1-1))
|
||
|
{
|
||
|
Ptemp->x2 = nx2;
|
||
|
goto next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
insert_area_after(Pdst_list, Pdst_list->Phead,
|
||
|
nx1, ny1, nx2, ny2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
next:
|
||
|
|
||
|
Parea2 = Parea2->Pnext;
|
||
|
}
|
||
|
|
||
|
Parea1 = Parea1->Pnext;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
Area_List_Ptr Area_List_create_optimal(Area_List_Ptr Plist)
|
||
|
{
|
||
|
Area_Ptr Parea = Plist->Phead->Pnext, Parea_after;
|
||
|
int num = 2;
|
||
|
Area_List_Ptr Pnew_list;
|
||
|
|
||
|
while (Parea != Plist->Ptail)
|
||
|
{
|
||
|
num++;
|
||
|
Parea = Parea->Pnext;
|
||
|
}
|
||
|
|
||
|
Pnew_list = Area_List_init(num);
|
||
|
|
||
|
Parea = Plist->Phead->Pnext;
|
||
|
|
||
|
Parea_after = Pnew_list->Phead;
|
||
|
|
||
|
while (Parea != Plist->Ptail)
|
||
|
{
|
||
|
Parea_after = insert_area_after(Pnew_list, Parea_after,
|
||
|
Parea->x1, Parea->y1,
|
||
|
Parea->x2, Parea->y2);
|
||
|
|
||
|
Parea = Parea->Pnext;
|
||
|
}
|
||
|
|
||
|
return (Pnew_list);
|
||
|
}
|
||
|
|
||
|
} // namespace crnlib
|