| | 1044 | PG_FUNCTION_INFO_V1(singlesidedbuffer); |
| | 1045 | Datum singlesidedbuffer(PG_FUNCTION_ARGS) |
| | 1046 | { |
| | 1047 | PG_LWGEOM *geom1; |
| | 1048 | double size; |
| | 1049 | GEOSGeometry *g1, *g3; |
| | 1050 | PG_LWGEOM *result; |
| | 1051 | int quadsegs = 8; /* the default */ |
| | 1052 | int nargs; |
| | 1053 | |
| | 1054 | enum |
| | 1055 | { |
| | 1056 | JOIN_ROUND = 1, |
| | 1057 | JOIN_MITRE = 2, |
| | 1058 | JOIN_BEVEL = 3 |
| | 1059 | }; |
| | 1060 | static const double DEFAULT_MITRE_LIMIT = 5.0; |
| | 1061 | static const int DEFAULT_JOIN_STYLE = JOIN_ROUND; |
| | 1062 | |
| | 1063 | double mitreLimit = DEFAULT_MITRE_LIMIT; |
| | 1064 | int joinStyle = DEFAULT_JOIN_STYLE; |
| | 1065 | int leftSide = 0; |
| | 1066 | char *param; |
| | 1067 | char *params = NULL; |
| | 1068 | |
| | 1069 | |
| | 1070 | PROFSTART(PROF_QRUN); |
| | 1071 | |
| | 1072 | geom1 = (PG_LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); |
| | 1073 | size = PG_GETARG_FLOAT8(1); |
| | 1074 | |
| | 1075 | nargs = PG_NARGS(); |
| | 1076 | |
| | 1077 | initGEOS(lwnotice, lwnotice); |
| | 1078 | |
| | 1079 | PROFSTART(PROF_P2G1); |
| | 1080 | g1 = (GEOSGeometry *)POSTGIS2GEOS(geom1); |
| | 1081 | PROFSTOP(PROF_P2G1); |
| | 1082 | |
| | 1083 | if (nargs > 2) |
| | 1084 | { |
| | 1085 | /* We strdup `cause we're going to modify it */ |
| | 1086 | params = pstrdup(PG_GETARG_CSTRING(2)); |
| | 1087 | |
| | 1088 | POSTGIS_DEBUGF(3, "Params: %s", params); |
| | 1089 | |
| | 1090 | for (param=params; ; param=NULL) |
| | 1091 | { |
| | 1092 | char *key, *val; |
| | 1093 | param = strtok(param, " "); |
| | 1094 | if ( param == NULL ) break; |
| | 1095 | POSTGIS_DEBUGF(3, "Param: %s", param); |
| | 1096 | |
| | 1097 | key = param; |
| | 1098 | val = strchr(key, '='); |
| | 1099 | if ( val == NULL || *(val+1) == '\0' ) |
| | 1100 | { |
| | 1101 | lwerror("Missing value for buffer " |
| | 1102 | "parameter %s", key); |
| | 1103 | break; |
| | 1104 | } |
| | 1105 | *val = '\0'; |
| | 1106 | ++val; |
| | 1107 | |
| | 1108 | POSTGIS_DEBUGF(3, "Param: %s : %s", key, val); |
| | 1109 | |
| | 1110 | if ( !strcmp(key, "join") ) |
| | 1111 | { |
| | 1112 | if ( !strcmp(val, "round") ) |
| | 1113 | { |
| | 1114 | joinStyle = JOIN_ROUND; |
| | 1115 | } |
| | 1116 | else if ( !strcmp(val, "mitre") || |
| | 1117 | !strcmp(val, "miter") ) |
| | 1118 | { |
| | 1119 | joinStyle = JOIN_MITRE; |
| | 1120 | } |
| | 1121 | else if ( !strcmp(val, "bevel") ) |
| | 1122 | { |
| | 1123 | joinStyle = JOIN_BEVEL; |
| | 1124 | } |
| | 1125 | else |
| | 1126 | { |
| | 1127 | lwerror("Invalid buffer end cap " |
| | 1128 | "style: %s (accept: " |
| | 1129 | "'round', 'mitre', 'miter' " |
| | 1130 | " or 'bevel'" |
| | 1131 | ")", val); |
| | 1132 | break; |
| | 1133 | } |
| | 1134 | } |
| | 1135 | else if ( !strcmp(key, "mitre_limit") || |
| | 1136 | !strcmp(key, "miter_limit") ) |
| | 1137 | { |
| | 1138 | /* mitreLimit is a float */ |
| | 1139 | mitreLimit = atof(val); |
| | 1140 | } |
| | 1141 | else if ( !strcmp(key, "quad_segs") ) |
| | 1142 | { |
| | 1143 | /* quadrant segments is an int */ |
| | 1144 | quadsegs = atoi(val); |
| | 1145 | } |
| | 1146 | else |
| | 1147 | { |
| | 1148 | lwerror("Invalid buffer parameter: %s (accept: " |
| | 1149 | "'join', 'mitre_limit', " |
| | 1150 | "'miter_limit and " |
| | 1151 | "'quad_segs')", key); |
| | 1152 | break; |
| | 1153 | } |
| | 1154 | } |
| | 1155 | |
| | 1156 | pfree(params); /* was pstrduped */ |
| | 1157 | |
| | 1158 | POSTGIS_DEBUGF(3, "joinStyle:%d mitreLimit:%g", |
| | 1159 | joinStyle, mitreLimit); |
| | 1160 | |
| | 1161 | } |
| | 1162 | if (nargs > 3) |
| | 1163 | { |
| | 1164 | leftSide = PG_GETARG_INT16(3); |
| | 1165 | // TODO debug !? |
| | 1166 | } |
| | 1167 | |
| | 1168 | PROFSTART(PROF_GRUN); |
| | 1169 | g3 = GEOSSingleSidedBuffer(g1, size, quadsegs, |
| | 1170 | joinStyle, mitreLimit, leftSide); |
| | 1171 | PROFSTOP(PROF_GRUN); |
| | 1172 | |
| | 1173 | if (g3 == NULL) |
| | 1174 | { |
| | 1175 | elog(ERROR,"GEOS singlesidedbuffer() threw an error!"); |
| | 1176 | GEOSGeom_destroy(g1); |
| | 1177 | PG_RETURN_NULL(); /* never get here */ |
| | 1178 | } |
| | 1179 | |
| | 1180 | POSTGIS_DEBUGF(3, "result: %s", GEOSGeomToWKT(g3)); |
| | 1181 | |
| | 1182 | GEOSSetSRID(g3, pglwgeom_getSRID(geom1)); |
| | 1183 | |
| | 1184 | PROFSTART(PROF_G2P); |
| | 1185 | result = GEOS2POSTGIS(g3, TYPE_HASZ(geom1->type)); |
| | 1186 | PROFSTOP(PROF_G2P); |
| | 1187 | |
| | 1188 | if (result == NULL) |
| | 1189 | { |
| | 1190 | GEOSGeom_destroy(g1); |
| | 1191 | GEOSGeom_destroy(g3); |
| | 1192 | elog(ERROR,"GEOS singlesidedbuffer() threw an error (result postgis geometry formation)!"); |
| | 1193 | PG_RETURN_NULL(); /* never get here */ |
| | 1194 | } |
| | 1195 | GEOSGeom_destroy(g1); |
| | 1196 | GEOSGeom_destroy(g3); |
| | 1197 | |
| | 1198 | |
| | 1199 | /* compressType(result); */ |
| | 1200 | |
| | 1201 | PROFSTOP(PROF_QRUN); |
| | 1202 | PROFREPORT("geos",geom1, NULL, result); |
| | 1203 | |
| | 1204 | PG_FREE_IF_COPY(geom1, 0); |
| | 1205 | |
| | 1206 | PG_RETURN_POINTER(result); |
| | 1207 | } |
| | 1208 | |
| | 1209 | |