int poly_c_center(gpc_vertex_list *vl, double *cx, double *cy){ gpc_vertex *v; double x=0.0, y=0.0, a; int i; for (i=0; i < vl->num_vertices-1; i++) { v = vl->vertex + i; a = v->x * (v+1)->y - (v+1)->x * v->y; x += (v->x + (v+1)->x) * a; y += (v->y + (v+1)->y) * a; } if (! poly_c_is_closed(vl)) { /* close the loop */ v = vl->vertex + (vl->num_vertices-1); a = v->x * vl->vertex->y - vl->vertex->x * v->y; x += (v->x + vl->vertex->x) * a; y += (v->y + vl->vertex->y) * a; } /* this algorithm needs ccw ordered points, so we have to calculate the order and multiply, what a waste of cpu power... If you know a better way, let me know... */ a = 6.0*poly_c_area(vl)*poly_c_orientation(vl); if (a == 0) return 1; *cx = x / a; *cy = y / a; return 0; }
int poly_p_center(gpc_polygon *p, double *cx, double *cy){ double *x, *y, *a, A=0.0, X=0.0, Y=0.0; int i; size_t s; s = sizeof(double)*p->num_contours; a = (double *)alloca(s); x = (double *)alloca(s); y = (double *)alloca(s); for (i=0; i < p->num_contours; i++) { a[i] = ((p->hole[i]) ? -1.0 : 1.0) * poly_c_area(p->contour+i); if (poly_c_center(p->contour+i, x+i, y+i) != 0) return 1; } for (i=0; i < p->num_contours; i++) A += a[i]; for (i=0; i < p->num_contours; i++) { X += a[i] * x[i]; Y += a[i] * y[i]; } if (A == 0) return 1; *cx = X / A; *cy = Y / A; return 0; }
double poly_p_area(gpc_polygon *p) { int i; double a = 0.0; for (i = 0; i < p->num_contours; i++) a += ((p->hole[i]) ? -1.0 : 1.0) * poly_c_area(p->contour+i); return a; }
static PyObject *Polygon_area(Polygon *self, PyObject *args) { int i=INDEF; if (! PyArg_ParseTuple(args, "|i", &i)) return Polygon_Raise(ERR_ARG); if (i!=INDEF) { if ((i >= 0) && (i < self->p->num_contours)) return Py_BuildValue("d", poly_c_area(self->p->contour+i)); else return Polygon_Raise(ERR_IND); } return Py_BuildValue("d", poly_p_area(self->p)); }
static PyObject *Polygon_sample(Polygon *self, PyObject *args) { PyObject *rng, *val1, *val2, *val3, *res; double A; if (! PyArg_ParseTuple(args, "O", &rng)) return Polygon_Raise(ERR_ARG); if (!PyCallable_Check(rng)) return Polygon_Raise(ERR_ARG); res = NULL; Py_INCREF(rng); // Sampling requires three random values val1 = val2 = val3 = NULL; val1 = PyObject_CallObject(rng, NULL); val2 = PyObject_CallObject(rng, NULL); val3 = PyObject_CallObject(rng, NULL); Py_DECREF(rng); if ((! PyFloat_Check(val1)) || (! PyFloat_Check(val2)) || (! PyFloat_Check(val3))) { Polygon_Raise(PolyError, "rng returned something other than a float"); goto cleanup; } A = poly_p_area(self->gpc_p); if (A == 0.0) { Polygon_Raise(PolyError, "cannot sample from a zero-area polygon"); goto cleanup; } else { gpc_tristrip *t = (gpc_tristrip *)alloca(sizeof(gpc_tristrip)); gpc_vertex_list *vl; gpc_vertex_list one_tri; int i, j; gpc_vertex *tri_verts; double a, b, c, px, py; t->num_strips = 0; t->strip = NULL; gpc_polygon_to_tristrip(self->gpc_p, t); A *= PyFloat_AS_DOUBLE(val1); one_tri.num_vertices = 3; for (i=0; i < t->num_strips; i++) { vl = t->strip + i; for (j=0; j < vl->num_vertices - 2; j++) { one_tri.vertex = vl->vertex + j; A -= poly_c_area(& one_tri); if (A <= 0.0) goto tri_found; } } tri_found: // sample a point from this triangle a = PyFloat_AS_DOUBLE(val2); b = PyFloat_AS_DOUBLE(val3); if ((a + b) > 1.0) { a = 1 - a; b = 1 - b; } c = 1 - a - b; tri_verts = one_tri.vertex; px = a * tri_verts[0].x + b * tri_verts[1].x + c * tri_verts[2].x; py = a * tri_verts[0].y + b * tri_verts[1].y + c * tri_verts[2].y; res = PyTuple_New(2); PyTuple_SetItem(res, 0, PyFloat_FromDouble(px)); PyTuple_SetItem(res, 1, PyFloat_FromDouble(py)); gpc_free_tristrip(t); } cleanup: Py_XDECREF(val1); Py_XDECREF(val2); Py_XDECREF(val3); return res; }