990{
991 GEOSBufferParams *bufferparams;
992 GEOSGeometry *g1, *g3 = NULL;
995 int quadsegs = 8;
996 int singleside = 0;
997 enum
998 {
999 ENDCAP_ROUND = 1,
1000 ENDCAP_FLAT = 2,
1001 ENDCAP_SQUARE = 3
1002 };
1003 enum
1004 {
1005 JOIN_ROUND = 1,
1006 JOIN_MITRE = 2,
1007 JOIN_BEVEL = 3
1008 };
1009 const double DEFAULT_MITRE_LIMIT = 5.0;
1010 const int DEFAULT_ENDCAP_STYLE = ENDCAP_ROUND;
1011 const int DEFAULT_JOIN_STYLE = JOIN_ROUND;
1012 double mitreLimit = DEFAULT_MITRE_LIMIT;
1013 int endCapStyle = DEFAULT_ENDCAP_STYLE;
1014 int joinStyle = DEFAULT_JOIN_STYLE;
1015
1017 double size = PG_GETARG_FLOAT8(1);
1018 text *params_text;
1019
1020 if (PG_NARGS() > 2)
1021 {
1022 params_text = PG_GETARG_TEXT_P(2);
1023 }
1024 else
1025 {
1026 params_text = cstring_to_text("");
1027 }
1028
1029
1031 {
1034 0, 0));
1035 PG_RETURN_POINTER(geometry_serialize(lwg));
1036 }
1037
1039
1041 {
1042 lwpgerror("Geometry contains invalid coordinates");
1043 PG_RETURN_NULL();
1044 }
1046
1048
1050 if (!g1)
1052
1053
1054 if (VARSIZE_ANY_EXHDR(params_text) > 0)
1055 {
1056 char *param;
1057 char *params = text_to_cstring(params_text);
1058
1059 for (param=params; ; param=NULL)
1060 {
1061 char *key, *val;
1062 param = strtok(param, " ");
1063 if (!param) break;
1064 POSTGIS_DEBUGF(3, "Param: %s", param);
1065
1066 key = param;
1067 val = strchr(key, '=');
1068 if (!val || *(val + 1) == '\0')
1069 {
1070 lwpgerror("Missing value for buffer parameter %s", key);
1071 break;
1072 }
1073 *val = '\0';
1074 ++val;
1075
1076 POSTGIS_DEBUGF(3, "Param: %s : %s", key, val);
1077
1078 if ( !strcmp(key, "endcap") )
1079 {
1080
1081
1082
1083 if ( !strcmp(val, "round") )
1084 {
1085 endCapStyle = ENDCAP_ROUND;
1086 }
1087 else if ( !strcmp(val, "flat") ||
1088 !strcmp(val, "butt") )
1089 {
1090 endCapStyle = ENDCAP_FLAT;
1091 }
1092 else if ( !strcmp(val, "square") )
1093 {
1094 endCapStyle = ENDCAP_SQUARE;
1095 }
1096 else
1097 {
1098 lwpgerror("Invalid buffer end cap "
1099 "style: %s (accept: "
1100 "'round', 'flat', 'butt' "
1101 "or 'square'"
1102 ")", val);
1103 break;
1104 }
1105
1106 }
1107 else if ( !strcmp(key, "join") )
1108 {
1109 if ( !strcmp(val, "round") )
1110 {
1111 joinStyle = JOIN_ROUND;
1112 }
1113 else if ( !strcmp(val, "mitre") ||
1114 !strcmp(val, "miter") )
1115 {
1116 joinStyle = JOIN_MITRE;
1117 }
1118 else if ( !strcmp(val, "bevel") )
1119 {
1120 joinStyle = JOIN_BEVEL;
1121 }
1122 else
1123 {
1124 lwpgerror("Invalid buffer end cap "
1125 "style: %s (accept: "
1126 "'round', 'mitre', 'miter' "
1127 " or 'bevel'"
1128 ")", val);
1129 break;
1130 }
1131 }
1132 else if ( !strcmp(key, "mitre_limit") ||
1133 !strcmp(key, "miter_limit") )
1134 {
1135
1136 mitreLimit = atof(val);
1137 }
1138 else if ( !strcmp(key, "quad_segs") )
1139 {
1140
1141 quadsegs = atoi(val);
1142 }
1143 else if ( !strcmp(key, "side") )
1144 {
1145 if ( !strcmp(val, "both") )
1146 {
1147 singleside = 0;
1148 }
1149 else if ( !strcmp(val, "left") )
1150 {
1151 singleside = 1;
1152 }
1153 else if ( !strcmp(val, "right") )
1154 {
1155 singleside = 1;
1156 size *= -1;
1157 }
1158 else
1159 {
1160 lwpgerror("Invalid side parameter: %s (accept: 'right', 'left', 'both')", val);
1161 break;
1162 }
1163 }
1164 else
1165 {
1166 lwpgerror(
1167 "Invalid buffer parameter: %s (accept: 'endcap', 'join', 'mitre_limit', 'miter_limit', 'quad_segs' and 'side')",
1168 key);
1169 break;
1170 }
1171 }
1172 pfree(params);
1173 }
1174
1175
1176 POSTGIS_DEBUGF(3, "endCap:%d joinStyle:%d mitreLimit:%g",
1177 endCapStyle, joinStyle, mitreLimit);
1178
1179 bufferparams = GEOSBufferParams_create();
1180 if (bufferparams)
1181 {
1182 if (GEOSBufferParams_setEndCapStyle(bufferparams, endCapStyle) &&
1183 GEOSBufferParams_setJoinStyle(bufferparams, joinStyle) &&
1184 GEOSBufferParams_setMitreLimit(bufferparams, mitreLimit) &&
1185 GEOSBufferParams_setQuadrantSegments(bufferparams, quadsegs) &&
1186 GEOSBufferParams_setSingleSided(bufferparams, singleside))
1187 {
1188 g3 = GEOSBufferWithParams(g1, bufferparams, size);
1189 }
1190 else
1191 {
1192 lwpgerror("Error setting buffer parameters.");
1193 }
1194 GEOSBufferParams_destroy(bufferparams);
1195 }
1196 else
1197 {
1198 lwpgerror("Error setting buffer parameters.");
1199 }
1200
1201 GEOSGeom_destroy(g1);
1202
1204
1205 POSTGIS_DEBUGF(3, "result: %s", GEOSGeomToWKT(g3));
1206
1208
1210 GEOSGeom_destroy(g3);
1211
1213 {
1214 elog(ERROR,"GEOS buffer() threw an error (result postgis geometry formation)!");
1215 PG_RETURN_NULL();
1216 }
1217
1218 PG_FREE_IF_COPY(geom1, 0);
1219 PG_RETURN_POINTER(
result);
1220}
char result[OUT_DOUBLE_BUFFER_SIZE]
int32_t gserialized_get_srid(const GSERIALIZED *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
int gserialized_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
void lwgeom_geos_error(const char *fmt,...)
void lwgeom_free(LWGEOM *geom)
int lwgeom_isfinite(const LWGEOM *lwgeom)
Check if a LWGEOM has any non-finite (NaN or Inf) coordinates.
LWPOLY * lwpoly_construct_empty(int32_t srid, char hasz, char hasm)
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
GSERIALIZED * GEOS2POSTGIS(GEOSGeom geom, char want3d)
GEOSGeometry * POSTGIS2GEOS(const GSERIALIZED *pglwgeom)
#define HANDLE_GEOS_ERROR(label)