Source of rectangle.c
static int min(int a, int b)
static int max(int a, int b)
rectangle* construct_rectangle(int ulx, int uly, int lrx, int lry, char* new_name)
void destruct_rectangle(rectangle* R)
void show_rectangle(rectangle* R)
void insert_rectangle_before(rectangle* S, rectangle* R)
void insert_rectangle_after(rectangle* S, rectangle* R)
void remove_rectangle_from_list(rectangle* R)
rectangle* find_rectangle_on_list(rectangle* L, char* re)
int area(rectangle* R)
int point_is_in_interval_P(int a, int b, int c)
int point_is_inside_rectangle_P(int x, int y, rectangle* R)
rectangle* construct_empty_list_of_rectangles(char* name)
void update_bounding_box(rectangle* L, rectangle* R)
void add_rectangle_to_list(rectangle* L, rectangle* R)
rectangle* remove_named_rectangle_from_list(rectangle* L, char* name)
void destroy_named_rectangle_on_list(rectangle* L, char* name)
rectangle* initial_rectangle_list_iterator(rectangle* list, state_rectangle_list_iterator** context)
int continue_rectangle_list_iterator(state_rectangle_list_iterator** context)
rectangle* next_rectangle_list_iterator(state_rectangle_list_iterator** context)
void reposition_rectangle_on_list(rectangle* list, rectangle* r, int ulx, int uly, int lrx, int lry)
rectangle* intersection_of_2_rectangles(rectangle* R1, rectangle* R2, char* name)
/* rectangle.c -- special rectangle support for gemsvnc */
/* See the include file "rectangle.h" for additional documentation. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rectangle.h"
#include "cmd_sockets.h"
/* stupidly, these are not defined elsewhere */
#define TRUE (!FALSE) /* the true truth value is the logical opposite of false */
#define FALSE (0) /* the false truth value */
/* min and max functions -- why aren't these built-in? */
static int min(int a, int b) { /* the minimum of 2 integers */
return a < b ? a : b;
}
static int max(int a, int b) { /* the maximum of 2 integers */
return a > b ? a : b;
}
/* Rectangle Methods */
rectangle* construct_rectangle(int ulx, int uly, int lrx, int lry, char* new_name) { /* construct a named rectangle with the
specified upper-left and lower-right
corners */
rectangle* R = (rectangle*)malloc(sizeof(rectangle)); /* allocate the memory for it */
int len = strlen(new_name); /* how long is its name? */
R->name = (char*)malloc(len + 1); /* make room for its name */
strcpy(R->name, new_name); /* remember its name */
R->next = R; /* make it live on a list of its own */
R->prev = R;
R->ul_x = ulx; /* initialize the corner coordinates */
R->ul_y = uly;
R->lr_x = lrx;
R->lr_y = lry;
return R; /* return the new rectangle */
}
void destruct_rectangle(rectangle* R) { /* destruct a rectangle */
free(R->name);
free(R);
}
void show_rectangle(rectangle* R) { /* show a rectangle in human readable form */
printf("rectangle \"%s\" <#%x> UL = (%d, %d) LR = (%d, %d)\n", R->name, (int) R, R->ul_x, R->ul_y, R->lr_x, R->lr_y);
}
void insert_rectangle_before(rectangle* S, rectangle* R) { /* insert R before S in the list S is on */
rectangle* Q;
if (S == NULL || R == NULL) { /* do the rectangles S and R both exist? */
return; /* no, do nothing */
}
Q = S->prev; /* get the predecessor of S */
Q->next = R; /* not a degenerate case, insert R before S and after Q */
R->prev = Q;
R->next = S;
S->prev = R;
}
void insert_rectangle_after(rectangle* S, rectangle* R) { /* insert R after S in the list S is on */
rectangle* Q;
if (S == NULL || R == NULL) { /* do the rectangles S and R both exist? */
return; /* no, do nothing */
}
Q = S->next; /* get the successor of S */
R->next = Q; /* not a degenerate case, insert R after S and before Q */
S->next = R;
R->prev = S;
Q->prev = R;
}
void remove_rectangle_from_list(rectangle* R) { /* remove R from whatever list it might be on */
rectangle* Q; /* next node after R */
rectangle* S; /* prev node before R */
if (R == NULL) { /* is there a rectangle R, */
return; /* no, do nothing */
}
/* NOTE: This will do unnecessary but harmless work if R is on a list by itself. */
S = (rectangle*)R->next; /* point to nodes around this one */
Q = (rectangle*)R->prev;
S->prev = Q; /* remove R from the list */
Q->next = S;
R->prev = R; /* say R is on a list of its own */
R->next = R;
}
rectangle* find_rectangle_on_list(rectangle* L, char* re) { /* determine whether a rectangle is on a list L */
static regex_t preg[4096]; /* compiled regular expression to match name */
int errcode;
rectangle* P;
if (L == NULL || re == NULL || strlen(re) == 0) { /* do both the list and the regular expression exist? */
return NULL; /* no, say not found! */
}
errcode = regcomp(preg, re, 0); /* compile the regular expression */
if (errcode != 0) { /* any errors? */
regfree(preg); /* free the compiled expression */
return NULL; /* yes, say not found! */
}
for (P = L->next; P != L; P = P->next) { /* traverse the list */
if (regexec(preg, P->name, 0, NULL, 0) == 0) { /* does the name match the regular expression? */
regfree(preg); /* yes, free the compiled expression */
return P; /* return that rectangle! */
}
}
regfree(preg); /* no match, free the compiled expression */
return NULL; /* say we did not find it! */
}
int area(rectangle* R) { /* return the area of a rectangle */
int width = R->lr_x - R->ul_x;
int height = R->lr_y - R->ul_y;
return width*height;
}
int point_is_in_interval_P(int a, int b, int c) { /* is b between a and c? */
int lb = a <= b;
int ub = b <= c;
int ans = lb && ub;
return ans;
}
int point_is_inside_rectangle_P(int x, int y, rectangle* R) { /* is the point inside the rectangle? */
int in_lr = point_is_in_interval_P(R->ul_x, x, R->lr_x);
int in_tb = point_is_in_interval_P(R->ul_y, y, R->lr_y);
int answer = in_lr && in_tb;
return answer;
}
/* The list of rectangles has a rectangle as its list head. This rectangle is the bounding-box for all the rectangles in the list. */
rectangle* construct_empty_list_of_rectangles(char* name) { /* construct the list head for a list of rectangles, initially
empty */
rectangle* head = construct_rectangle(INT_MAX, INT_MAX, INT_MIN, INT_MIN, name); /* make a rectangle with an impossible bounding box */
/* If p0 is the upper-left corner, and p1 is the lower-right corner, then no point can ever be in that rectangle. */
return head; /* return the new list head */
}
void update_bounding_box(rectangle* L, rectangle* R) { /* update bounding box in list head L to included rectangle R */
L->ul_x = min(L->ul_x, R->ul_x); /* upper left corner */
L->ul_y = min(L->ul_y, R->ul_y);
L->lr_x = max(L->lr_x, R->lr_x); /* lower right corner */
L->lr_y = max(L->lr_y, R->lr_y);
}
void add_rectangle_to_list(rectangle* L, rectangle* R) { /* add a rectangle to a list of rectangles. */
insert_rectangle_after(L, R); /* put it there */
update_bounding_box(L, R); /* update bounding box */
return;
}
rectangle* remove_named_rectangle_from_list(rectangle* L, char* name) { /* remove a rectangle with the same corners */
rectangle* R = find_rectangle_on_list(L, name); /* try to find the named rectangle on the list */
rectangle* S;
if (R != NULL) { /* find one? */
remove_rectangle_from_list(R); /* yes, remove it from the list */
/* Now we must determine if the bounding box needs to be contracted. If any of the 4 coordinates of the deleted rectangle,
ur.x, ur.y, lr.x, and lr.y, match the corresponding coordinate of the bounding box exactly, then we need to recompute the
bounding box. */
if ( L->ul_x == R->ul_x /* do any of the coordinates match exactly? */
|| L->ul_y == R->ul_y
|| L->lr_x == R->lr_x
|| L->lr_y == R->lr_y ) {
L->ul_x = INT_MAX; /* reset bounding box to impossible */
L->ul_y = INT_MAX;
L->lr_x = INT_MIN;
L->lr_y = INT_MIN;
for (S = L->next; S != L; S = S->next) { /* yes, for each rectangle remaining on the list */
update_bounding_box(L, S); /* update the bounding box to include that rectangle */
}
}
}
return R; /* return what we found */
}
void destroy_named_rectangle_on_list(rectangle* L, char* name) { /* search and destroy a named rectangle */
rectangle* S = remove_named_rectangle_from_list(L, name); /* search for it */
if (S != NULL) { /* found it? */
destruct_rectangle(S); /* yes, get rid of it */
}
}
/* The iterator over lists of rectangles.
Usage:
rectangle* list;
rectangle* R;
state_rectangle_list_iterator* context;
for (R = initial_rectangle_list_iterator(list, &context);
continue_rectangle_list_iterator(&context);
R = next_rectangle_list_iterator(&context)) {
do_something(R);
}
*/
rectangle* initial_rectangle_list_iterator(rectangle* list, state_rectangle_list_iterator** context) { /* initialize an iterator */
*context = (state_rectangle_list_iterator*)malloc(sizeof(state_rectangle_list_iterator)); /* allocate a context save area */
(*context)->head = list; /* remember termination point */
(*context)->current = list->next; /* initialize first item */
return (*context)->current; /* return first item */
}
int continue_rectangle_list_iterator(state_rectangle_list_iterator** context) { /* test an iterator for non-completion */
if ((*context)->current == (*context)->head) { /* are we done? */
free(*context); /* yes, release the context save area */
return FALSE; /* say not to continue */
} else {
return TRUE; /* no, not done, say to continue */
}
}
rectangle* next_rectangle_list_iterator(state_rectangle_list_iterator** context) { /* get the next item */
(*context)->current = ((*context)->current)->next; /* update to point to next item */
return (*context)->current; /* return next item */
}
void reposition_rectangle_on_list(rectangle* list, rectangle* r, int ulx, int uly, int lrx, int lry) {
state_rectangle_list_iterator* context;
r->ul_x = ulx; /* put rectangle at new place on screen */
r->ul_y = uly;
r->lr_x = lrx;
r->lr_y = lry;
list->ul_x = INT_MAX; /* reset bounding box to impossible */
list->ul_y = INT_MAX;
list->lr_x = INT_MIN;
list->lr_y = INT_MIN;
for (r = initial_rectangle_list_iterator(list, &context); /* re-compute the bounding box */
continue_rectangle_list_iterator(&context);
r = next_rectangle_list_iterator(&context)) {
update_bounding_box(list, r);
}
}
rectangle* intersection_of_2_rectangles(rectangle* R1, rectangle* R2, char* name) {
int ulx = max(R1->ul_x, R2->ul_x); /* compute coordinates of intersection rectangle */
int uly = max(R1->ul_y, R2->ul_y);
int lrx = min(R1->lr_x, R2->lr_x);
int lry = min(R1->lr_y, R2->lr_y);
if (ulx > lrx /* do the rectangles actually intersect? */
|| uly > lry) {
return NULL; /* no, return no rectangle */
} else {
return construct_rectangle(ulx, uly, lrx, lry, name); /* yes, return the rectangle of intersection */
}
}