double reg_calc_area_complex_polygon( regShape* shape ) { regRegion *temp; regShape *copy; double area; fprintf(stderr, "WARNING: Calculating area of a complex polygon "); fprintf(stderr,"using brute force method. This may take a long time.\n"); // Create a new region with just the polygon temp = regCreateRegion(NULL, NULL); copy = shape->copy(shape); // Analytic area calculations always computes the area of the interior // of the shape. copy->include = regInclude; regAddShape(temp, regAND, copy); // Calc the extent of the polygon then trim the bounds to fit within // the original region if available regCalcExtentPolygon(shape, temp->xregbounds, temp->yregbounds); if (shape->region) { reg_trim_extent(temp->xregbounds, temp->yregbounds, shape->region->xregbounds, shape->region->yregbounds, 0); } area = regComputePixellatedArea(temp, temp->xregbounds, temp->yregbounds, 1); // Free and return regFree(temp); return area; }
/* Invert a region We come here with a region structure containing a linked list of "shapes" Region->shapeA->shapeB->shapeC->shapeD etc Each shape has a flag which indicates its relation to the previous shape, whether AND or OR. AND operations take precedence over OR, so we can view the shape list as a series of AND terms separated by OR operations: P*Q+R*S*T+W*Z = (P*Q)+(R*S*T)+(W*Z) This inversion function has two stages. First it creates a linked list of terms. A term is a set of shapes grouped by AND. Successive entries in the term list are joined by OR. From DeMorgan's laws: ___________________ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ (P*Q)+(R*S*T)+(W*Z) = P*R*W + P*R*Z + P*S*W + P*S*Z + P*T*W + P*T*Z + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Q*R*W + Q*R*Z + Q*S*W + Q*S*Z + Q*T*W + Q*T*Z Stated more simply, the left hand side is composed of all combinations of one shape chosen from each term, with each shape negated. This is NOT the most compact way to write the results of DeMorgan's transformation, but is a representation which requires no explicit grouping syntax: AND over OR precedence being adequate. The second stage of this function cycles through the term list, pulling shapes out, negating them, and adding them to the inverted region shape list. */ regRegion* regInvert( regRegion* inRegion ) { double fx[2] ={ -DBL_MAX, DBL_MAX }; double fy[2] ={ -DBL_MAX, DBL_MAX }; regRegion* Region; regShape* Shape; regShape* inShape; struct regTerm *term; struct regTerm *nextTerm; struct regTerm *firstTerm; struct regTerm *safeTerm; #ifndef TRUE #define TRUE 1 #define FALSE 0 typedef int boolean; #endif boolean done; // Copy shapes if ( !inRegion ) { return NULL; } Region = regCreateRegion(NULL, NULL); if (inRegion->shape == NULL) { return Region; } inShape = inRegion->shape; // parse the region shapes in "terms" connected by OR term = (struct regTerm *) (malloc(sizeof(struct regTerm))); term->next = NULL; term->prev = NULL; firstTerm = term; // initialize first term term->first = inShape; term->current = inShape; term->last = inShape; // add shapes to the current term while (inShape->next != NULL) { // look for OR glue if (inShape->component != inShape->next->component) { // found it - finish off current term, and start new one term->last = inShape; // remember this shape as "last' // malloc new term nextTerm = (struct regTerm *) (malloc(sizeof(struct regTerm))); // init new term nextTerm->first = inShape->next; nextTerm->current = inShape->next; term->next = nextTerm; nextTerm->prev = term; nextTerm->next = NULL; // new term is current term */ term = nextTerm; } inShape = inShape->next; } term->last = inShape; // now do the inversion math done = FALSE; while (!done) { // get a shape from each term term = firstTerm; do { // remember our current term (we will advance past it) safeTerm = term; Shape = regCopyShape(term->current ); Shape->include = Shape->include ? regExclude : regInclude; // first shape in term is "joined" to predecessor (nothing) by OR if (term == firstTerm) { regAddShape( Region, regOR, Shape ); } else { // all other terms join shapes by AND regAddShape( Region, regAND, Shape ); } term = term->next; } while (term != NULL); // we have now got a shape from each term term = safeTerm; // advance to next shape in last term */ if (term->current != term->last) { term->current = term->current->next; } else { // already at last shape, reset current term to first if (term != firstTerm) { term->current = term->first; } else { done = TRUE; } while (term != firstTerm) { // go to previous term and advance or reset as appropriate term = term->prev; // any shapes left? if (term->current != term->last) { // yes advance and break out of loop term->current = term->current->next; break; } else { // no - reset to first shape...*/ if (term != firstTerm) { term->current = term->first; } else { // ...unless this is the first term, // in which case we are done done = TRUE; } } } } } // dispose of our parsing structures term = firstTerm; do { nextTerm = term->next; free(term); term = nextTerm; } while (term != NULL); regExtent(Region, fx, fy, Region->xregbounds, Region->yregbounds); return Region; }
regRegion* regUnionRegion( regRegion* Region1, regRegion* Region2 ) { double fx[2] ={ -DBL_MAX, DBL_MAX }; double fy[2] ={ -DBL_MAX, DBL_MAX }; regRegion* region; regShape* shape; regShape* inShape; regMath glue; long lastComponent; int haveMore; /* Copy shapes */ if ( !Region1 ) { if ( !Region2 ) { return NULL; } return regCopyRegion( Region2 ); } /* If regions are equal just return copy of one */ if ( regCompareRegion( Region1, Region2 )) { return regCopyRegion( Region1 ); } /* Make a new region with all the combined components of the input regions */ /* - Put USER defined shapes first in the series. */ region = regCreateRegion(NULL, NULL); /* Transfer Region components with USER shapes. */ /* NOTE: expectation is that USER shapes are first on the component */ haveMore = 1; inShape = Region1->shape; while ( inShape != NULL ) { if ( inShape->type == regMASK ) { glue = regOR; lastComponent = inShape->component; while ( inShape && inShape->component == lastComponent ) { shape = regCopyShape(inShape); regAddShape( region, glue, shape ); glue = regAND; inShape = inShape->next; } } else { inShape = reg_next_component( inShape ); } if ( (inShape == NULL) && haveMore ) { /* scan second region components */ inShape = Region2->shape; haveMore = 0; } } /* Transfer Region components Non-USER shapes.*/ haveMore = 1; inShape = Region1->shape; while ( inShape != NULL ) { if ( inShape->type == regMASK ) { inShape = reg_next_component( inShape ); } else { glue = regOR; lastComponent = inShape->component; while ( inShape && inShape->component == lastComponent ) { shape = regCopyShape(inShape); regAddShape( region, glue, shape ); glue = regAND; inShape = inShape->next; } } if ( (inShape == NULL) && haveMore ) { /* scan second region components */ inShape = Region2->shape; haveMore = 0; } } /* re-calculate the region extent */ regExtent(region, fx, fy, region->xregbounds, region->yregbounds); return region; }