/*************************************************************************
*
*N Module VPFCLIP
*
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* Purpose:
*P
* This module geometrically clips an edge table to a given map
* extent and creates a new edge table. It does not attempt to
* maintain topology, nor does it maintain its relationship to
* any feature tables associated with it. Its intent is to be
* used only for the Library Reference coverage. It may also serve
* as a basic starting point for a complete GIS clipping algorithm.
*E
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* Parameters:
*A
* N/A
*E
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* History:
*H
* Barry Michaels Dec 1991 DOS Turbo C
*E
*************************************************************************/
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <alloc.h>
#include "vpftable.h"
#include "vpfview.h"
#include "vpfprim.h"
typedef struct {
float x1, y1, x2, y2;
} line_segment_type;
/* Defined in VPFPTPLY.C */
int intersect( line_segment_type l1, line_segment_type l2,
float *xint, float *yint );
edge_rec_type create_edge_rec( row_type row, vpf_table_type edge_table );
/* Determine if a line segment intersects a box. */
/* If so return the intersection coordinate in the parameter list. */
static int box_intersection( line_segment_type lseg,
extent_type extent,
coordinate_type *coord )
{
line_segment_type boxseg;
float xint, yint;
boxseg.x1 = extent.x1;
boxseg.y1 = extent.y1;
boxseg.x2 = extent.x2;
boxseg.y2 = extent.y1;
if (intersect(lseg,boxseg,&xint,&yint)) {
coord->x = xint;
coord->y = yint;
return TRUE;
}
boxseg.x1 = extent.x2;
boxseg.y1 = extent.y1;
boxseg.x2 = extent.x2;
boxseg.y2 = extent.y2;
if (intersect(lseg,boxseg,&xint,&yint)) {
coord->x = xint;
coord->y = yint;
return TRUE;
}
boxseg.x1 = extent.x2;
boxseg.y1 = extent.y2;
boxseg.x2 = extent.x1;
boxseg.y2 = extent.y2;
if (intersect(lseg,boxseg,&xint,&yint)) {
coord->x = xint;
coord->y = yint;
return TRUE;
}
boxseg.x1 = extent.x1;
boxseg.y1 = extent.y2;
boxseg.x2 = extent.x1;
boxseg.y2 = extent.y1;
if (intersect(lseg,boxseg,&xint,&yint)) {
coord->x = xint;
coord->y = yint;
return TRUE;
}
return FALSE;
}
/* Replace the given coordinate string into the given edge row */
/* and write the new row to the specified edge table. */
static void write_edge_record( long int id, coordinate_type *coord,
long int ncoord, row_type row,
vpf_table_type *table )
{
int ID_, COORD_;
ID_ = table_pos("ID",*table);
COORD_ = table_pos("COORDINATES",*table);
put_table_element(ID_, row, *table, &id, 1);
put_table_element(COORD_, row, *table, coord, ncoord);
write_next_row(row,table);
}
#define WITHIN(x,y,ext) ((x>=ext.x1)&&(x<=ext.x2)&& \
(y>=ext.y1)&&(y<=ext.y2))
/*************************************************************************
*
*N vpf_edge_clip
*
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* Purpose:
*P
* This function clips an edge table to the given extent and writes
* the clipped table to the specified output path.
* NOTE: If a segment of an edge in the EDG table has both a beginning
* point and ending point outside of the given extent, and the line
* segment passes through the extent, the segment will not be written
* out to the new edge table.
*E
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* Parameters:
*A
* covpath <input> == (char *) path to the coverage of the edge table.
* extent <input> == (extent_type) clipping extent.
* outpath <input> == (char *) output path for the clipped edge table.
*E
*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*
* History:
*H
* Barry Michaels Dec 1991 Original Version DOS Turbo C
*E
*************************************************************************/
void vpf_edge_clip( char *covpath, extent_type extent, char *outpath )
{
vpf_table_type in, out;
row_type row;
edge_rec_type inedge, outedge;
long int i,j,n,id;
line_segment_type lseg;
coordinate_type coord;
char path[255], *def;
float xmin, xmax, ymin, ymax;
/* Standardize extent, Lower Left, Upper Right */
xmin = (float)min(extent.x1,extent.x2);
xmax = (float)max(extent.x1,extent.x2);
ymin = (float)min(extent.y1,extent.y2);
ymax = (float)max(extent.y1,extent.y2);
extent.x1 = xmin;
extent.y1 = ymin;
extent.x2 = xmax;
extent.y2 = ymax;
sprintf(path,"%sedg",covpath);
in = vpf_open_table(path,disk,"rb",NULL);
rewind(in.fp);
fread(&n,sizeof(n),1,in.fp);
def = (char *)vpfmalloc((n+1)*sizeof(char));
fread(def,sizeof(char),n,in.fp);
def[n] = '\0';
sprintf(path,"%sedg",outpath);
out = vpf_open_table(path,disk,"wb",def);
for (i=1,id=1;i<=in.nrows;i++) {
row = get_row( i, in );
inedge = create_edge_rec( row, in );
if (!inedge.coord) {
free_row(row,in);
continue;
}
outedge.coord = (coordinate_type *)malloc(inedge.npts*sizeof(
coordinate_type));
if (!outedge.coord) {
free(inedge.coord);
free_row(row,in);
continue;
}
n = 0;
for (j=0;j<inedge.npts;j++) {
if (WITHIN(inedge.coord[j].x,inedge.coord[j].y,extent)) {
/* Current coordinate within extent */
if (j > 0) {
if (!WITHIN(inedge.coord[j-1].x,inedge.coord[j-1].y,
extent)) {
/* Previous coordinate was not in the extent - */
/* create an intersection vertex */
lseg.x1 = inedge.coord[j-1].x;
lseg.y1 = inedge.coord[j-1].y;
lseg.x2 = inedge.coord[j].x;
lseg.y2 = inedge.coord[j].y;
if (box_intersection(lseg,extent,&coord)) {
outedge.coord[n].x = coord.x;
outedge.coord[n].y = coord.y;
} else {
outedge.coord[n].x = lseg.x1;
outedge.coord[n].y = lseg.y1;
}
n++;
}
}
outedge.coord[n].x = inedge.coord[j].x;
outedge.coord[n].y = inedge.coord[j].y;
n++;
} else {
if (j > 0) {
if (WITHIN(inedge.coord[j-1].x,inedge.coord[j-1].y,extent)) {
/* The coordinate is not within the extent and */
/* the previous one was - Create an intersection */
/* vertex point and write the current edge record. */
lseg.x1 = inedge.coord[j-1].x;
lseg.y1 = inedge.coord[j-1].y;
lseg.x2 = inedge.coord[j].x;
lseg.y2 = inedge.coord[j].y;
if (box_intersection(lseg,extent,&coord)) {
outedge.coord[n].x = coord.x;
outedge.coord[n].y = coord.y;
} else {
outedge.coord[n].x = lseg.x2;
outedge.coord[n].y = lseg.y2;
}
/* Break the edge in (at least) two */
n++;
write_edge_record( id, outedge.coord, n, row, &out );
id++;
n=0;
}
}
}
}
free(inedge.coord);
if (n > 0) {
write_edge_record( id, outedge.coord, n, row, &out );
id++;
}
free(outedge.coord);
free_row(row,in);
}
vpf_close_table(&in);
vpf_close_table(&out);
}