static int msProjectShapeLine(projectionObj *in, projectionObj *out, shapeObj *shape, int line_index) { int i; pointObj lastPoint, thisPoint, wrkPoint, firstPoint; lineObj *line = shape->line + line_index; lineObj *line_out = line; int valid_flag = 0; /* 1=true, -1=false, 0=unknown */ int numpoints_in = line->numpoints; int line_alloc = numpoints_in; int wrap_test; wrap_test = out != NULL && out->proj != NULL && pj_is_latlong(out->proj) && !pj_is_latlong(in->proj); line->numpoints = 0; if( numpoints_in > 0 ) firstPoint = line->point[0]; memset( &lastPoint, 0, sizeof(lastPoint) ); /* -------------------------------------------------------------------- */ /* Loop over all input points in linestring. */ /* -------------------------------------------------------------------- */ for( i=0; i < numpoints_in; i++ ) { int ms_err; wrkPoint = thisPoint = line->point[i]; ms_err = msProjectPoint(in, out, &wrkPoint ); /* -------------------------------------------------------------------- */ /* Apply wrap logic. */ /* -------------------------------------------------------------------- */ if( wrap_test && i > 0 && ms_err != MS_FAILURE ) { double dist; pointObj pt1Geo; if( line_out->numpoints > 0 ) pt1Geo = line_out->point[0]; else pt1Geo = wrkPoint; /* this is a cop out */ dist = wrkPoint.x - pt1Geo.x; if( fabs(dist) > 180.0 && msTestNeedWrap( thisPoint, firstPoint, pt1Geo, in, out ) ) { if( dist > 0.0 ) wrkPoint.x -= 360.0; else if( dist < 0.0 ) wrkPoint.x += 360.0; } } /* -------------------------------------------------------------------- */ /* Put result into output line with appropriate logic for */ /* failure breaking lines, etc. */ /* -------------------------------------------------------------------- */ if( ms_err == MS_FAILURE ) { /* We have started out invalid */ if( i == 0 ) { valid_flag = -1; } /* valid data has ended, we need to work out the horizon */ else if( valid_flag == 1 ) { pointObj startPoint, endPoint; startPoint = lastPoint; endPoint = thisPoint; if( msProjectSegment( in, out, &startPoint, &endPoint ) == MS_SUCCESS ) { line_out->point[line_out->numpoints++] = endPoint; } valid_flag = -1; } /* Still invalid ... */ else if( valid_flag == -1 ) { /* do nothing */ } } else { /* starting out valid. */ if( i == 0 ) { line_out->point[line_out->numpoints++] = wrkPoint; valid_flag = 1; } /* Still valid, nothing special */ else if( valid_flag == 1 ) { line_out->point[line_out->numpoints++] = wrkPoint; } /* we have come over the horizon, figure out where, start newline*/ else { pointObj startPoint, endPoint; startPoint = lastPoint; endPoint = thisPoint; if( msProjectSegment( in, out, &endPoint, &startPoint ) == MS_SUCCESS ) { lineObj newLine; /* force pre-allocation of lots of points room */ if( line_out->numpoints > 0 && shape->type == MS_SHAPE_LINE ) { newLine.numpoints = numpoints_in - i + 1; newLine.point = line->point; msAddLine( shape, &newLine ); /* new line is now lineout, but start without any points */ line_out = shape->line + shape->numlines-1; line_out->numpoints = 0; /* the shape->line array is realloc, refetch "line" */ line = shape->line + line_index; } else if( line_out == line && line->numpoints >= i-2 ) { newLine.numpoints = numpoints_in; newLine.point = line->point; msAddLine( shape, &newLine ); line = shape->line + line_index; line_out = shape->line + shape->numlines-1; line_out->numpoints = line->numpoints; line->numpoints = 0; /* * Now realloc this array large enough to hold all * the points we could possibly need to add. */ line_alloc = line_alloc * 2; line_out->point = (pointObj *) realloc(line_out->point, sizeof(pointObj) * line_alloc); } line_out->point[line_out->numpoints++] = startPoint; } line_out->point[line_out->numpoints++] = wrkPoint; valid_flag = 1; } } lastPoint = thisPoint; } /* -------------------------------------------------------------------- */ /* Make sure that polygons are closed, even if the trip over */ /* the horizon left them unclosed. */ /* -------------------------------------------------------------------- */ if( shape->type == MS_SHAPE_POLYGON && line_out->numpoints > 2 && (line_out->point[0].x != line_out->point[line_out->numpoints-1].x || line_out->point[0].y != line_out->point[line_out->numpoints-1].y) ) { /* make a copy because msAddPointToLine can realloc the array */ pointObj sFirstPoint = line_out->point[0]; msAddPointToLine( line_out, &sFirstPoint ); } return(MS_SUCCESS); }
shapeObj* msSmoothShapeSIA(shapeObj *shape, int ss, int si, char *preprocessing) { int i, j; pointObj *p; double *coeff; shapeObj *newShape; newShape = (shapeObj *) msSmallMalloc(sizeof (shapeObj)); msInitShape(newShape); if (ss < 3) ss = 3; if (si < 1) si = 1; /* Apply preprocessing */ if (preprocessing) { if (strcasecmp(preprocessing, "all") == 0) processShapePathDistance(shape, MS_TRUE); else if (strcasecmp(preprocessing, "angle") == 0) processShapePathDistance(shape, MS_FALSE); } p = (pointObj *) msSmallMalloc(ss*sizeof(pointObj)); coeff = (double *) msSmallMalloc(ss*sizeof (double)); for (i=0;i<si;++i) { shapeObj initialShape; if (si > 1 && i>0) { msInitShape(&initialShape); msCopyShape(shape, &initialShape); /* Clean our shape object */ for (j=0; j < newShape->numlines; ++j) free(newShape->line[j].point); newShape->numlines = 0; if (newShape->line) { free(newShape->line); newShape->line = NULL; } shape = &initialShape; } for (j=0;j<shape->numlines;++j) { int k, ws, res; lineObj newLine = {0,NULL}; lineWindow lw; /* determine if we can use the ss for this line */ ws = ss; if (ws >= shape->line[j].numpoints) { ws = shape->line[j].numpoints-1; } if (ws%2==0) ws-=1; initLineWindow(&lw, &shape->line[j], ws); msAddLine(newShape, &newLine); coeff[lw.index] = 1; for (k=0;k<lw.index;++k) { coeff[lw.index+(k+1)] = coeff[lw.index-k]/2; coeff[lw.index-(k+1)] = coeff[lw.index+k]/2; } while ((res = nextLineWindow(&lw)) != MS_DONE) { double sum_x=0, sum_y=0, sum = 0; pointObj point; int k = 0; if (res == MS_FALSE) { /* invalid window */ msAddPointToLine(&newShape->line[j], lw.points[lw.index]); continue; } /* Apply Coefficient */ p[lw.index] = *lw.points[lw.index]; for (k=0; k<lw.index; ++k) { p[lw.index-(k+1)] = *lw.points[lw.index-(k+1)]; p[lw.index-(k+1)].x *= coeff[lw.index-(k+1)]; p[lw.index-(k+1)].y *= coeff[lw.index-(k+1)]; p[lw.index+(k+1)] = *lw.points[lw.index+(k+1)]; p[lw.index+(k+1)].x *= coeff[lw.index+(k+1)]; p[lw.index+(k+1)].y *= coeff[lw.index+(k+1)]; } for (k=0; k<lw.size; ++k) { sum += coeff[k]; sum_x += p[k].x; sum_y += p[k].y; } point.x = sum_x/sum; point.y = sum_y/sum; msAddPointToLine(&newShape->line[j], &point); } freeLineWindow(&lw); } if (i>0) { msFreeShape(shape); shape = newShape; } } free(p); free(coeff); return newShape; }
static int msProjectShapeLine(projectionObj *in, projectionObj *out, shapeObj *shape, int line_index) { int i; pointObj lastPoint, thisPoint, wrkPoint; lineObj *line = shape->line + line_index; lineObj *line_out = line; int valid_flag = 0; /* 1=true, -1=false, 0=unknown */ int numpoints_in = line->numpoints; int line_alloc = numpoints_in; int wrap_test; #ifdef USE_PROJ_FASTPATHS #define MAXEXTENT 20037508.34 #define M_PIby360 .0087266462599716479 #define MAXEXTENTby180 111319.4907777777777777777 #define p_x line->point[i].x #define p_y line->point[i].y if(in->wellknownprojection == wkp_lonlat && out->wellknownprojection == wkp_gmerc) { for( i = line->numpoints-1; i >= 0; i-- ) { p_x *= MAXEXTENTby180; p_y = log(tan((90 + p_y) * M_PIby360)) * MS_RAD_TO_DEG; p_y *= MAXEXTENTby180; if (p_x > MAXEXTENT) p_x = MAXEXTENT; if (p_x < -MAXEXTENT) p_x = -MAXEXTENT; if (p_y > MAXEXTENT) p_y = MAXEXTENT; if (p_y < -MAXEXTENT) p_y = -MAXEXTENT; } return MS_SUCCESS; } if(in->wellknownprojection == wkp_gmerc && out->wellknownprojection == wkp_lonlat) { for( i = line->numpoints-1; i >= 0; i-- ) { if (p_x > MAXEXTENT) p_x = MAXEXTENT; else if (p_x < -MAXEXTENT) p_x = -MAXEXTENT; if (p_y > MAXEXTENT) p_y = MAXEXTENT; else if (p_y < -MAXEXTENT) p_y = -MAXEXTENT; p_x = (p_x / MAXEXTENT) * 180; p_y = (p_y / MAXEXTENT) * 180; p_y = MS_RAD_TO_DEG * (2 * atan(exp(p_y * MS_DEG_TO_RAD)) - MS_PI2); } msComputeBounds( shape ); /* fixes bug 1586 */ return MS_SUCCESS; } #undef p_x #undef p_y #endif wrap_test = out != NULL && out->proj != NULL && pj_is_latlong(out->proj) && !pj_is_latlong(in->proj); line->numpoints = 0; memset( &lastPoint, 0, sizeof(lastPoint) ); /* -------------------------------------------------------------------- */ /* Loop over all input points in linestring. */ /* -------------------------------------------------------------------- */ for( i=0; i < numpoints_in; i++ ) { int ms_err; wrkPoint = thisPoint = line->point[i]; ms_err = msProjectPoint(in, out, &wrkPoint ); /* -------------------------------------------------------------------- */ /* Apply wrap logic. */ /* -------------------------------------------------------------------- */ if( wrap_test && i > 0 && ms_err != MS_FAILURE ) { double dist; pointObj pt1Geo; if( line_out->numpoints > 0 ) pt1Geo = line_out->point[line_out->numpoints-1]; else pt1Geo = wrkPoint; /* this is a cop out */ dist = wrkPoint.x - pt1Geo.x; if( fabs(dist) > 180.0 && msTestNeedWrap( thisPoint, lastPoint, pt1Geo, in, out ) ) { if( dist > 0.0 ) wrkPoint.x -= 360.0; else if( dist < 0.0 ) wrkPoint.x += 360.0; } } /* -------------------------------------------------------------------- */ /* Put result into output line with appropriate logic for */ /* failure breaking lines, etc. */ /* -------------------------------------------------------------------- */ if( ms_err == MS_FAILURE ) { /* We have started out invalid */ if( i == 0 ) { valid_flag = -1; } /* valid data has ended, we need to work out the horizon */ else if( valid_flag == 1 ) { pointObj startPoint, endPoint; startPoint = lastPoint; endPoint = thisPoint; if( msProjectSegment( in, out, &startPoint, &endPoint ) == MS_SUCCESS ) { line_out->point[line_out->numpoints++] = endPoint; } valid_flag = -1; } /* Still invalid ... */ else if( valid_flag == -1 ) { /* do nothing */ } } else { /* starting out valid. */ if( i == 0 ) { line_out->point[line_out->numpoints++] = wrkPoint; valid_flag = 1; } /* Still valid, nothing special */ else if( valid_flag == 1 ) { line_out->point[line_out->numpoints++] = wrkPoint; } /* we have come over the horizon, figure out where, start newline*/ else { pointObj startPoint, endPoint; startPoint = lastPoint; endPoint = thisPoint; if( msProjectSegment( in, out, &endPoint, &startPoint ) == MS_SUCCESS ) { lineObj newLine; /* force pre-allocation of lots of points room */ if( line_out->numpoints > 0 && shape->type == MS_SHAPE_LINE ) { newLine.numpoints = numpoints_in - i + 1; newLine.point = line->point; msAddLine( shape, &newLine ); /* new line is now lineout, but start without any points */ line_out = shape->line + shape->numlines-1; line_out->numpoints = 0; /* the shape->line array is realloc, refetch "line" */ line = shape->line + line_index; } else if( line_out == line && line->numpoints >= i-2 ) { newLine.numpoints = numpoints_in; newLine.point = line->point; msAddLine( shape, &newLine ); line = shape->line + line_index; line_out = shape->line + shape->numlines-1; line_out->numpoints = line->numpoints; line->numpoints = 0; /* * Now realloc this array large enough to hold all * the points we could possibly need to add. */ line_alloc = line_alloc * 2; line_out->point = (pointObj *) realloc(line_out->point, sizeof(pointObj) * line_alloc); } line_out->point[line_out->numpoints++] = startPoint; } line_out->point[line_out->numpoints++] = wrkPoint; valid_flag = 1; } } lastPoint = thisPoint; } /* -------------------------------------------------------------------- */ /* Make sure that polygons are closed, even if the trip over */ /* the horizon left them unclosed. */ /* -------------------------------------------------------------------- */ if( shape->type == MS_SHAPE_POLYGON && line_out->numpoints > 2 && (line_out->point[0].x != line_out->point[line_out->numpoints-1].x || line_out->point[0].y != line_out->point[line_out->numpoints-1].y) ) { /* make a copy because msAddPointToLine can realloc the array */ pointObj sFirstPoint = line_out->point[0]; msAddPointToLine( line_out, &sFirstPoint ); } return(MS_SUCCESS); }
/* Pre-Processing of a shape. It modifies the shape by adding intermediate points where a loop is detected to improve the smoothing result. */ static int processShapePathDistance(shapeObj *shape, int force) { shapeObj initialShape, *newShape; int i; /* initial shape to process */ msInitShape(&initialShape); msCopyShape(shape, &initialShape); newShape = shape; /* we modify the shape object directly */ shape = &initialShape; /* Clean our shape object */ for (i= 0; i < newShape->numlines; i++) free(newShape->line[i].point); newShape->numlines = 0; if (newShape->line) free(newShape->line); for (i=0;i<shape->numlines;++i) { const int windowSize = 5; int res; lineWindow lw; lineObj line = {0, NULL}; initLineWindow(&lw, &shape->line[i], windowSize); msAddLine(newShape, &line); while ((res = nextLineWindow(&lw)) != MS_DONE) { double ratio = 0; pointObj point; if (lw.lineIsRing && lw.pos==lw.line->numpoints-1) { point = newShape->line[i].point[0]; msAddPointToLine(&newShape->line[i], &point); continue; } if (res == MS_FALSE) { /* invalid window */ msAddPointToLine(&newShape->line[i], lw.points[lw.index]); continue; } if (!force) ratio = computePathDistanceRatio(lw.points, windowSize); if (force || (ratio > 1.3)) { point.x = (lw.line->point[lw.pos].x + lw.points[lw.index-1]->x)/2; point.y = (lw.line->point[lw.pos].y + lw.points[lw.index-1]->y)/2; msAddPointToLine(&newShape->line[i], &point); } point = lw.line->point[lw.pos]; msAddPointToLine(&newShape->line[i], &point); if (force || (ratio > 1.3)) { point.x = (lw.line->point[lw.pos].x + lw.points[lw.index+1]->x)/2; point.y = (lw.line->point[lw.pos].y + lw.points[lw.index+1]->y)/2; msAddPointToLine(&newShape->line[i], &point); } } freeLineWindow(&lw); } msFreeShape(shape); return MS_SUCCESS; }