Exemple #1
0
static void gts_triangulate_test_stuff()
{
	gdouble v[4][3] = {
		{0.0, 0.0, 0.0},
		{0.0, 3.0, 0.0},
		{3.0, 3.0, 0.0},
		{1.0, 1.0, 0.0}
	};
	
	int i; 
	GtsVertex *vtx[4];
	GCList *polygon = NULL;
	GtsVector orient; 
	GCList *p; 
	
	for (i = 0; i < 4; ++i) {
		vtx[i] = gts_vertex_new(gts_vertex_class(), v[i][0],v[i][1],v[i][2]); 
		polygon = g_clist_append(polygon, vtx[i]); 
	}
	g_assert(g_clist_length(polygon));
	g_assert(gts_polygon_orientation(polygon, orient));	

	g_assert(orient[0] == 0 && orient[1] == 0 && orient[2] < 0); 

	p = g_clist_next(polygon); 
	g_assert(is_convex(GTS_POINT(p->prev->data), GTS_POINT(p->data),GTS_POINT(p->next->data), orient));
	g_assert(is_inside(GTS_POINT(vtx[0]), GTS_POINT(vtx[1]), GTS_POINT(vtx[2]), GTS_POINT(vtx[3])));
	g_assert(!is_inside(GTS_POINT(vtx[0]), GTS_POINT(vtx[1]), GTS_POINT(vtx[3]), GTS_POINT(vtx[2])));

	g_clist_free(p); 
	for (i = 0; i < 4; ++i) 
		gts_object_destroy(GTS_OBJECT(vtx[i])); 
		
}
Exemple #2
0
AirspacePolygon::AirspacePolygon(const std::vector<GeoPoint>& pts,
  const bool prune)
  :AbstractAirspace(POLYGON)
{
  if (pts.size()<2) {
    m_is_convex = true;
  } else {
    TaskProjection task_projection; // note dummy blank projection
    for (std::vector<GeoPoint>::const_iterator v = pts.begin();
         v != pts.end(); ++v) {
      m_border.push_back(SearchPoint(*v, task_projection));
    }
    // ensure airspace is closed
    GeoPoint p_start = pts[0];
    GeoPoint p_end = *(pts.end()-1);
    if (p_start != p_end) {
      m_border.push_back(SearchPoint(p_start, task_projection));
    }
    
    if (prune) {
      // only for testing
      prune_interior(m_border);
      m_is_convex = true;
    } else {
      m_is_convex = is_convex(m_border);
    }
  }
}
Exemple #3
0
static gboolean add_ear(GtsSurface *s, GtsEdgePool *pool, GCList *p, GCList *polygon, GtsVector orientation)
{
	GtsPoint *v1, *v2, *v3;  
	GCList *i; 
	// ears are convex
	GCList *pp = p->prev;
	GCList *pn = p->next;
	
	v1 = GTS_POINT(pp->data);
	v2 = GTS_POINT(p->data);
	v3 = GTS_POINT(pn->data);
	GTS_IS_POINT(v1); 
	GTS_IS_POINT(v2); 
	GTS_IS_POINT(v3);

	if ( !is_convex(v1, v2, v3, orientation) ) {
		g_debug("concave face (%6.2f %6.2f %6.2f) (%6.2f %6.2f %6.2f) (%6.2f %6.2f %6.2f)",
			v1->x, v1->y, v1->z, v2->x, v2->y, v2->z, v3->x, v3->y, v3->z); 
		return FALSE;
	}
	
	i = polygon; 
	
	do {
		GtsPoint *p1 = GTS_POINT(i->data);
		if (p1 != v1 && p1 != v2 && p1 != v3) {
			GtsPoint *p0 = GTS_POINT(i->prev->data);
			GtsPoint *p2 = GTS_POINT(i->next->data);
			
			if (!is_convex(p0, p1, p2, orientation) && is_inside(v1, v2, v3, p1)) {
				g_debug("reject face\n"); 
				return FALSE;
			}
		}
		i = g_clist_next(i); 
	} while (i != polygon); 

	add_face_from_polygon_corner(s, pool, GTS_VERTEX(v1), GTS_VERTEX(v2), GTS_VERTEX(v3)); 
	return TRUE; 
}
// The objective here is to inset all of the edges by the given distance, and then
// remove any invalid inset edges by detecting right-hand turns. In a ccw polygon,
// we should only be making left-hand turns (for cw polygons, we use the winding
// parameter to reverse this). We detect this by checking whether the second intersection
// on an edge is closer to its tail than the first one.
//
// We might also have the case that there is no intersection between two neighboring inset edges.
// In this case, one edge will lie to the right of the other and should be discarded along with
// its previous intersection (if any).
//
// Note: the assumption is that inputPolygon is convex and has no coincident points.
//
bool SkInsetConvexPolygon(const SkPoint* inputPolygonVerts, int inputPolygonSize,
                          std::function<SkScalar(int index)> insetDistanceFunc,
                          SkTDArray<SkPoint>* insetPolygon) {
    if (inputPolygonSize < 3) {
        return false;
    }

    int winding = get_winding(inputPolygonVerts, inputPolygonSize);
    if (0 == winding) {
        return false;
    }

    // set up
    struct EdgeData {
        InsetSegment fInset;
        SkPoint      fIntersection;
        SkScalar     fTValue;
        bool         fValid;
    };

    SkAutoSTMalloc<64, EdgeData> edgeData(inputPolygonSize);
    for (int i = 0; i < inputPolygonSize; ++i) {
        int j = (i + 1) % inputPolygonSize;
        SkOffsetSegment(inputPolygonVerts[i], inputPolygonVerts[j],
                        insetDistanceFunc(i), insetDistanceFunc(j),
                        winding,
                        &edgeData[i].fInset.fP0, &edgeData[i].fInset.fP1);
        edgeData[i].fIntersection = edgeData[i].fInset.fP0;
        edgeData[i].fTValue = SK_ScalarMin;
        edgeData[i].fValid = true;
    }

    int prevIndex = inputPolygonSize - 1;
    int currIndex = 0;
    int insetVertexCount = inputPolygonSize;
    while (prevIndex != currIndex) {
        if (!edgeData[prevIndex].fValid) {
            prevIndex = (prevIndex + inputPolygonSize - 1) % inputPolygonSize;
            continue;
        }

        SkScalar s, t;
        SkPoint intersection;
        if (compute_intersection(edgeData[prevIndex].fInset, edgeData[currIndex].fInset,
                                 &intersection, &s, &t)) {
            // if new intersection is further back on previous inset from the prior intersection
            if (s < edgeData[prevIndex].fTValue) {
                // no point in considering this one again
                edgeData[prevIndex].fValid = false;
                --insetVertexCount;
                // go back one segment
                prevIndex = (prevIndex + inputPolygonSize - 1) % inputPolygonSize;
            // we've already considered this intersection, we're done
            } else if (edgeData[currIndex].fTValue > SK_ScalarMin &&
                       intersection.equalsWithinTolerance(edgeData[currIndex].fIntersection,
                                                          1.0e-6f)) {
                break;
            } else {
                // add intersection
                edgeData[currIndex].fIntersection = intersection;
                edgeData[currIndex].fTValue = t;

                // go to next segment
                prevIndex = currIndex;
                currIndex = (currIndex + 1) % inputPolygonSize;
            }
        } else {
            // if prev to right side of curr
            int side = winding*compute_side(edgeData[currIndex].fInset.fP0,
                                            edgeData[currIndex].fInset.fP1,
                                            edgeData[prevIndex].fInset.fP1);
            if (side < 0 && side == winding*compute_side(edgeData[currIndex].fInset.fP0,
                                                         edgeData[currIndex].fInset.fP1,
                                                         edgeData[prevIndex].fInset.fP0)) {
                // no point in considering this one again
                edgeData[prevIndex].fValid = false;
                --insetVertexCount;
                // go back one segment
                prevIndex = (prevIndex + inputPolygonSize - 1) % inputPolygonSize;
            } else {
                // move to next segment
                edgeData[currIndex].fValid = false;
                --insetVertexCount;
                currIndex = (currIndex + 1) % inputPolygonSize;
            }
        }
    }

    // store all the valid intersections that aren't nearly coincident
    // TODO: look at the main algorithm and see if we can detect these better
    static constexpr SkScalar kCleanupTolerance = 0.01f;

    insetPolygon->reset();
    insetPolygon->setReserve(insetVertexCount);
    currIndex = -1;
    for (int i = 0; i < inputPolygonSize; ++i) {
        if (edgeData[i].fValid && (currIndex == -1 ||
            !edgeData[i].fIntersection.equalsWithinTolerance((*insetPolygon)[currIndex],
                                                             kCleanupTolerance))) {
            *insetPolygon->push() = edgeData[i].fIntersection;
            currIndex++;
        }
    }
    // make sure the first and last points aren't coincident
    if (currIndex >= 1 &&
        (*insetPolygon)[0].equalsWithinTolerance((*insetPolygon)[currIndex],
                                                 kCleanupTolerance)) {
        insetPolygon->pop();
    }
    SkASSERT(is_convex(*insetPolygon));

    return (insetPolygon->count() >= 3);
}