mirror of
git://projects.qi-hardware.com/cae-tools.git
synced 2024-12-23 08:39:33 +02:00
poly2d/: Yet another 2D polygon library (WIP)
This commit is contained in:
parent
c2bfbd5a5e
commit
dfa85075e8
105
poly2d/Makefile
Normal file
105
poly2d/Makefile
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#
|
||||||
|
# Makefile - Makefile of libpoly2d
|
||||||
|
#
|
||||||
|
# Written 2012 by Werner Almesberger
|
||||||
|
# Copyright 2012 by Werner Almesberger
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
|
||||||
|
PREFIX ?= /usr/local
|
||||||
|
|
||||||
|
SHELL = /bin/bash
|
||||||
|
|
||||||
|
LIB = libpoly2d.a
|
||||||
|
OBJS = v2d_intersect.o v2d_line_distance.o \
|
||||||
|
p2d_area.o p2d_area_holes.o \
|
||||||
|
p2d_attrib.o p2d_contains_point.o p2d_contains_poly.o \
|
||||||
|
p2d_copy.o p2d_free.o p2d_gnuplot.o p2d_make.o p2d_offset.o p2d_hsort.o
|
||||||
|
|
||||||
|
CFLAGS_WARN = -Wall -Wshadow -Wmissing-prototypes \
|
||||||
|
-Wmissing-declarations -Wno-format-zero-length
|
||||||
|
|
||||||
|
CFLAGS = $(CFLAGS_WARN) -g
|
||||||
|
CXXFLAGS = -Wall -frounding-math
|
||||||
|
LDFLAGS =
|
||||||
|
LDLIBS = -lm
|
||||||
|
|
||||||
|
# ----- Verbosity control -----------------------------------------------------
|
||||||
|
|
||||||
|
CC_normal := $(CC)
|
||||||
|
CXX_normal := $(CXX)
|
||||||
|
AR_normal := $(AR)
|
||||||
|
DEPEND_normal := $(CPP) $(CFLAGS) -MM -MG
|
||||||
|
|
||||||
|
CC_quiet = @echo " CC " $@ && $(CC_normal)
|
||||||
|
CXX_quiet = @echo " CXX " $@ && $(CXX_normal)
|
||||||
|
AR_quiet = @echo " AR " $@ && $(AR_normal)
|
||||||
|
DEPEND_quiet = @$(DEPEND_normal)
|
||||||
|
|
||||||
|
ifeq ($(V),1)
|
||||||
|
CC = $(CC_normal)
|
||||||
|
CXX = $(CXX_normal)
|
||||||
|
AR = $(AR_normal)
|
||||||
|
DEPEND = $(DEPEND_normal)
|
||||||
|
else
|
||||||
|
CC = $(CC_quiet)
|
||||||
|
CXX = $(CXX_quiet)
|
||||||
|
AR = $(AR_quiet)
|
||||||
|
DEPEND = $(DEPEND_quiet)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# ----- Rules -----------------------------------------------------------------
|
||||||
|
|
||||||
|
.PHONY: all clean spotless
|
||||||
|
.PHONY: test tests valgrind
|
||||||
|
|
||||||
|
all: $(LIB)
|
||||||
|
|
||||||
|
$(LIB): $(OBJS)
|
||||||
|
$(AR) cr $@ $^
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJS) $(OBJS:.o=.d)
|
||||||
|
|
||||||
|
spotless: clean
|
||||||
|
rm -f $(LIB)
|
||||||
|
|
||||||
|
# ----- Install / uninstall ---------------------------------------------------
|
||||||
|
|
||||||
|
install: all
|
||||||
|
mkdir -p $(DESTDIR)/$(PREFIX)/bin/
|
||||||
|
install -m 755 $(MAIN) $(DESTDIR)/$(PREFIX)/bin/
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -f $(DESTDIR)/$(PREFIX)/bin/$(MAIN)
|
||||||
|
|
||||||
|
# ----- Dependencies ----------------------------------------------------------
|
||||||
|
|
||||||
|
# compile and generate dependencies, from fped, based on
|
||||||
|
# http://scottmcpeak.com/autodepend/autodepend.html
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) -c $(CFLAGS) $*.c -o $*.o
|
||||||
|
$(DEPEND) $*.c | \
|
||||||
|
sed -e \
|
||||||
|
'/^\(.*:\)\? */{p;s///;s/ *\\\?$$/ /;s/ */:\n/g;H;}' \
|
||||||
|
-e '$${g;p;}' -e d >$*.d; \
|
||||||
|
[ "$${PIPESTATUS[*]}" = "0 0" ] || { rm -f $*.d; exit 1; }
|
||||||
|
|
||||||
|
-include $(OBJS:.o=.d)
|
||||||
|
|
||||||
|
# ----- Tests -----------------------------------------------------------------
|
||||||
|
|
||||||
|
test tests: all
|
||||||
|
LANG= sh -c \
|
||||||
|
'passed=0 && cd test && \
|
||||||
|
for n in [a-z]*; do \
|
||||||
|
[ $$n != core ] && SCRIPT=$$n . ./$$n; done; \
|
||||||
|
echo "Passed all $$passed tests"'
|
||||||
|
|
||||||
|
valgrind:
|
||||||
|
VALGRIND="valgrind -q" $(MAKE) tests
|
54
poly2d/README
Normal file
54
poly2d/README
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
poly2d - Yet another 2D polygon library
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
Why do we need another 2D polygon library, if there are already CGAL,
|
||||||
|
Boost, Clipper, GPC, ... ?
|
||||||
|
|
||||||
|
All the above are either written in a weird language, are under a
|
||||||
|
non-Free license, or simply don't provide the feature set we need
|
||||||
|
here. poly2d is written in C, doesn't depend on non-standard
|
||||||
|
libraries, and is licensed under the GPL (will change to LGPL).
|
||||||
|
|
||||||
|
poly2d serves itself liberally from code already in cameo but
|
||||||
|
provides a simpler and cleaner interface. The first objective is
|
||||||
|
to provide the tools to replace the (badly broken) area filling
|
||||||
|
operation in cameo. Later, poly2d could replace more parts of
|
||||||
|
cameo.
|
||||||
|
|
||||||
|
poly2d puts more emphasis on simplicity than on performance. Some
|
||||||
|
functions expect clockwise closed polygons that don't self-intersect.
|
||||||
|
The table below shows the capabilities
|
||||||
|
|
||||||
|
Open Counter-clockwise
|
||||||
|
| Concave Min. vertices
|
||||||
|
| | Self-intersect
|
||||||
|
| | | | |
|
||||||
|
Y Y Y Y 0 p2d_contains_poly(b), p2d_free, p2d_free_all,
|
||||||
|
p2d_is_closed, p2d_copy, p2d_reverse, p2d_vertices,
|
||||||
|
p2d_write_gnuplog, p2d_write_gnuplot_all
|
||||||
|
Y Y Y Y 1 p2d_read_gnuplot
|
||||||
|
- Y Y Y 0 p2d_simplify
|
||||||
|
- Y - Y 3 p2d_is_cw
|
||||||
|
- Y - - 3 p2d_contains_point, p2d_contains_poly (a),
|
||||||
|
- Y - # 3 p2d_area*, p2d_offset*
|
||||||
|
|
||||||
|
# CGAL uses ccw, poly2d uses cw. Need to switch.
|
||||||
|
|
||||||
|
Not yet implemented:
|
||||||
|
- p2d_simplify (low priority - the offsetting from CGAL already covers
|
||||||
|
the main use case)
|
||||||
|
|
||||||
|
Not yet specified:
|
||||||
|
- subtraction (do we actually need it ?)
|
||||||
|
|
||||||
|
Other:
|
||||||
|
- change the license from GPL to LGPL
|
||||||
|
- change ccw to cw
|
||||||
|
- make sure CGAL is only fed ccw ploygons and cw holes
|
||||||
|
- transform CGAL's idea of outer polygons into something we can use
|
||||||
|
- use more meaningful offset/overlap model for area fill
|
||||||
|
- check for memory leaks
|
||||||
|
- try to generate dependencies also for *.cpp
|
||||||
|
|
||||||
|
Prerequisite:
|
||||||
|
libcgal-dev
|
65
poly2d/cgal_helper.h
Normal file
65
poly2d/cgal_helper.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* cgal_helper.h - Conversions between poly2d and CGAL
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 by Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CGAL_HELPER_H
|
||||||
|
#define CGAL_HELPER_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* References:
|
||||||
|
* http://www.cgal.org/Manual/latest/examples/Straight_skeleton_2/
|
||||||
|
* Create_saop_from_polygon_with_holes_2.cpp
|
||||||
|
* http://www.cgal.org/Manual/latest/examples/Straight_skeleton_2/print.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "poly2d.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Polygon_with_holes_2.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||||
|
|
||||||
|
typedef CGAL::Polygon_2<K> Polygon_2;
|
||||||
|
|
||||||
|
|
||||||
|
static inline Polygon_2 p2d_to_P2(const struct p2d *p)
|
||||||
|
{
|
||||||
|
const struct v2d *v;
|
||||||
|
Polygon_2 np;
|
||||||
|
|
||||||
|
v = p->v;
|
||||||
|
do {
|
||||||
|
np.push_back(K::Point_2(v->x, v->y));
|
||||||
|
v = v->next;
|
||||||
|
}
|
||||||
|
while (v != p->v);
|
||||||
|
return np;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline struct p2d *P2_to_p2d(Polygon_2 p)
|
||||||
|
{
|
||||||
|
struct p2d *np;
|
||||||
|
|
||||||
|
np = p2d_new();
|
||||||
|
for (Polygon_2::Vertex_iterator vit = p.vertices_begin();
|
||||||
|
vit != p.vertices_end(); ++vit)
|
||||||
|
p2d_append(np, v2d_new(vit->x(), vit->y()));
|
||||||
|
p2d_close(np);
|
||||||
|
return np;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !CGAL_HELPER_H */
|
44
poly2d/p2d_area.c
Normal file
44
poly2d/p2d_area.c
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* p2d_area.c - Fill a set of nested polygons
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "poly2d.h"
|
||||||
|
#include "p2d_hsort.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void recurse_area(struct p2d_hier *t, double offset, double overlap,
|
||||||
|
struct p2d ***last)
|
||||||
|
{
|
||||||
|
const struct p2d *p, *h;
|
||||||
|
|
||||||
|
for (p = &t->p; p; p = p->next) {
|
||||||
|
h = &p2d_to_hier(p)->holes->p;
|
||||||
|
p2d_area_holes_append(p, h, offset, overlap, last);
|
||||||
|
while (h) {
|
||||||
|
recurse_area(p2d_to_hier(h)->holes, offset, overlap,
|
||||||
|
last);
|
||||||
|
h = h->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct p2d *p2d_area(const struct p2d *p, double offset, double overlap)
|
||||||
|
{
|
||||||
|
struct p2d_hier *t;
|
||||||
|
struct p2d *res = NULL, **last = &res;
|
||||||
|
|
||||||
|
t = p2d_hsort(p);
|
||||||
|
recurse_area(t, offset, overlap, &last);
|
||||||
|
p2d_hier_free(t);
|
||||||
|
return res;
|
||||||
|
}
|
101
poly2d/p2d_area_holes.cpp
Normal file
101
poly2d/p2d_area_holes.cpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* p2d_area_holes.cpp - Fill an area with holes
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 by Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* References:
|
||||||
|
* http://www.cgal.org/Manual/latest/examples/Straight_skeleton_2/
|
||||||
|
* Create_skeleton_and_offset_polygons_with_holes_2.cpp
|
||||||
|
* http://www.cgal.org/Manual/latest/examples/Straight_skeleton_2/print.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "poly2d.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "cgal_helper.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Polygon_with_holes_2.h>
|
||||||
|
#include <CGAL/create_offset_polygons_from_polygon_with_holes_2.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||||
|
|
||||||
|
typedef CGAL::Polygon_2<K> Polygon_2;
|
||||||
|
typedef CGAL::Polygon_with_holes_2<K> Polygon_with_holes;
|
||||||
|
|
||||||
|
typedef boost::shared_ptr<Polygon_with_holes> PolygonPtr;
|
||||||
|
|
||||||
|
typedef std::vector<PolygonPtr> PolygonPtrVector;
|
||||||
|
|
||||||
|
struct p2d *res = NULL, **last = &res, *np;
|
||||||
|
|
||||||
|
|
||||||
|
static void append_poly(Polygon_2 poly, struct p2d ***last)
|
||||||
|
{
|
||||||
|
**last = P2_to_p2d(poly);
|
||||||
|
*last = &(**last)->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void recurse_area(Polygon_with_holes poly, double curr_off,
|
||||||
|
double next_off, struct p2d ***last)
|
||||||
|
{
|
||||||
|
PolygonPtrVector tmp =
|
||||||
|
CGAL::create_interior_skeleton_and_offset_polygons_with_holes_2(
|
||||||
|
curr_off, poly);
|
||||||
|
|
||||||
|
for (PolygonPtrVector::const_iterator pit = tmp.begin();
|
||||||
|
pit != tmp.end(); ++pit) {
|
||||||
|
append_poly((*pit)->outer_boundary(), last);
|
||||||
|
recurse_area(**pit, next_off, next_off, last);
|
||||||
|
|
||||||
|
for (Polygon_with_holes::Hole_const_iterator
|
||||||
|
hit = (*pit)->holes_begin();
|
||||||
|
hit != (*pit)->holes_end(); ++hit) {
|
||||||
|
append_poly(*hit, last);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void p2d_area_holes_append(const struct p2d *p,
|
||||||
|
const struct p2d *holes, double offset, double overlap,
|
||||||
|
struct p2d ***last)
|
||||||
|
{
|
||||||
|
const struct p2d *h;
|
||||||
|
|
||||||
|
assert(p2d_is_closed(p));
|
||||||
|
Polygon_with_holes poly(p2d_to_P2(p));
|
||||||
|
|
||||||
|
for (h = holes; h; h = h->next) {
|
||||||
|
assert(p2d_is_closed(h));
|
||||||
|
poly.add_hole(p2d_to_P2(h));
|
||||||
|
}
|
||||||
|
|
||||||
|
recurse_area(poly, offset, offset-overlap, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" struct p2d *p2d_area_holes(const struct p2d *p,
|
||||||
|
const struct p2d *holes, double offset, double overlap)
|
||||||
|
{
|
||||||
|
struct p2d *res = NULL, **last = &res;
|
||||||
|
|
||||||
|
p2d_area_holes_append(p, holes, offset, overlap, &last);
|
||||||
|
return res;
|
||||||
|
}
|
122
poly2d/p2d_attrib.c
Normal file
122
poly2d/p2d_attrib.c
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* p2d_attrib.c - Determine various polygon attributes
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "poly2d.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Angle in counter-clockwise direction to turn at point B when coming from A
|
||||||
|
* in order to face towards C.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static double angle_3(const struct v2d *a, const struct v2d *b,
|
||||||
|
const struct v2d *c)
|
||||||
|
{
|
||||||
|
double ax, ay, bx, by;
|
||||||
|
double aa, bb;
|
||||||
|
double angle;
|
||||||
|
|
||||||
|
ax = b->x-a->x;
|
||||||
|
ay = b->y-a->y;
|
||||||
|
bx = c->x-b->x;
|
||||||
|
by = c->y-b->y;
|
||||||
|
|
||||||
|
aa = hypot(ax, ay);
|
||||||
|
bb = hypot(bx, by);
|
||||||
|
|
||||||
|
angle = acos((ax*bx+ay*by)/aa/bb)/M_PI*180.0;
|
||||||
|
|
||||||
|
return (ax*by-ay*bx) >= 0 ? angle : -angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we predominantly turn to the right, then the path must be clockwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int p2d_is_cw(const struct p2d *p)
|
||||||
|
{
|
||||||
|
const struct v2d *v;
|
||||||
|
double a = 0;
|
||||||
|
|
||||||
|
assert(p2d_vertices(p) >= 3);
|
||||||
|
assert(p2d_is_closed(p));
|
||||||
|
assert(p2d_no_intersect(p));
|
||||||
|
|
||||||
|
v = p->v;
|
||||||
|
do {
|
||||||
|
a += angle_3(v, v->next, v->next->next);
|
||||||
|
v = v->next;
|
||||||
|
}
|
||||||
|
while (v != p->v);
|
||||||
|
return a < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2d_is_closed(const struct p2d *p)
|
||||||
|
{
|
||||||
|
return p->v == p->last || p->last->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Known bug: if the polygon intersects on a vertex, the intersection may
|
||||||
|
* go unnoticed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int p2d_no_intersect(const struct p2d *p)
|
||||||
|
{
|
||||||
|
const struct v2d *v, *u;
|
||||||
|
|
||||||
|
v = p->v;
|
||||||
|
while (v) {
|
||||||
|
u = v->next;
|
||||||
|
if (!u || u == p->v)
|
||||||
|
return 1;
|
||||||
|
u = u->next;
|
||||||
|
if (!u || u == p->v)
|
||||||
|
return 1;
|
||||||
|
while (u && u->next) {
|
||||||
|
if (v2d_intersect(v, v->next, u, u->next,
|
||||||
|
NULL, NULL) > 0)
|
||||||
|
return 0;
|
||||||
|
u = u->next;
|
||||||
|
if (u == p->v)
|
||||||
|
break;
|
||||||
|
if (u->next == v)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
v = v->next;
|
||||||
|
if (v == p->v)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2d_vertices(const struct p2d *p)
|
||||||
|
{
|
||||||
|
const struct v2d *v;
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
v = p->v;
|
||||||
|
while (v) {
|
||||||
|
n++;
|
||||||
|
v = v->next;
|
||||||
|
if (v == p->v)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
56
poly2d/p2d_contains_point.c
Normal file
56
poly2d/p2d_contains_point.c
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* p2d_contains_point.c - Determine whether polygon contains point/polygon
|
||||||
|
*
|
||||||
|
* Based on the algorithm by W. Randolph Franklin
|
||||||
|
* http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
||||||
|
* which is distributed under the following license, similar to the 3-clause
|
||||||
|
* BSD license:
|
||||||
|
*
|
||||||
|
* Copyright (c) 1970-2003, Wm. Randolph Franklin
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimers.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. The name of W. Randolph Franklin may not be used to endorse or promote
|
||||||
|
* products derived from this Software without specific prior written
|
||||||
|
* permission.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "poly2d.h"
|
||||||
|
|
||||||
|
|
||||||
|
int p2d_contains_point(const struct p2d *p, const struct v2d *v)
|
||||||
|
{
|
||||||
|
const struct v2d *j, *i;
|
||||||
|
int in = 0;
|
||||||
|
|
||||||
|
j = p->v;
|
||||||
|
do {
|
||||||
|
i = j->next;
|
||||||
|
if (((i->y > v->y) != (j->y > v->y)) &&
|
||||||
|
(v->x < (j->x-i->x)*(v->y-i->y)/
|
||||||
|
(j->y-i->y)+i->x))
|
||||||
|
in = !in;
|
||||||
|
j = i;
|
||||||
|
}
|
||||||
|
while (j != p->v);
|
||||||
|
return in;
|
||||||
|
}
|
38
poly2d/p2d_contains_poly.c
Normal file
38
poly2d/p2d_contains_poly.c
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* p2d_contains_poly.c - Determine whether polygon contains other polygon
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "poly2d.h"
|
||||||
|
|
||||||
|
|
||||||
|
int p2d_contains_poly(const struct p2d *a, const struct p2d *b)
|
||||||
|
{
|
||||||
|
const struct v2d *v;
|
||||||
|
int in = 0, out = 0;
|
||||||
|
|
||||||
|
assert(p2d_is_closed(a));
|
||||||
|
v = b->v;
|
||||||
|
while (v) {
|
||||||
|
if (p2d_contains_point(a, v))
|
||||||
|
in++;
|
||||||
|
else
|
||||||
|
out++;
|
||||||
|
v = v->next;
|
||||||
|
if (v == b->v)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (in && out)
|
||||||
|
return -1;
|
||||||
|
return !out;
|
||||||
|
}
|
95
poly2d/p2d_copy.c
Normal file
95
poly2d/p2d_copy.c
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* p2d_copy.c - Copy a polygon, with or without reversing it
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "poly2d.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct p2d *p2d_copy(const struct p2d *p)
|
||||||
|
{
|
||||||
|
struct p2d *np;
|
||||||
|
const struct v2d *v;
|
||||||
|
struct v2d *nv, **last;
|
||||||
|
|
||||||
|
np = alloc_type(struct p2d);
|
||||||
|
np->v = NULL;
|
||||||
|
np->last = NULL;
|
||||||
|
np->next = NULL;
|
||||||
|
|
||||||
|
last = &np->v;
|
||||||
|
v = p->v;
|
||||||
|
while (v) {
|
||||||
|
nv = alloc_type(struct v2d);
|
||||||
|
nv->x = v->x;
|
||||||
|
nv->y = v->y;
|
||||||
|
nv->next = NULL;
|
||||||
|
*last = nv;
|
||||||
|
last = &nv->next;
|
||||||
|
|
||||||
|
np->last = nv;
|
||||||
|
|
||||||
|
v = v->next;
|
||||||
|
if (v == p->v)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (v)
|
||||||
|
*last = np->v;
|
||||||
|
return np;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct p2d *p2d_copy_all(const struct p2d *p)
|
||||||
|
{
|
||||||
|
struct p2d *res = NULL, **last = &res;
|
||||||
|
|
||||||
|
while (p) {
|
||||||
|
*last = p2d_copy(p);
|
||||||
|
last = &(*last)->next;
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct p2d *p2d_reverse(const struct p2d *p)
|
||||||
|
{
|
||||||
|
struct p2d *np;
|
||||||
|
const struct v2d *v;
|
||||||
|
struct v2d *nv;
|
||||||
|
|
||||||
|
np = alloc_type(struct p2d);
|
||||||
|
np->v = NULL;
|
||||||
|
np->last = NULL;
|
||||||
|
np->next = NULL;
|
||||||
|
|
||||||
|
v = p->v;
|
||||||
|
while (v) {
|
||||||
|
nv = alloc_type(struct v2d);
|
||||||
|
nv->x = v->x;
|
||||||
|
nv->y = v->y;
|
||||||
|
nv->next = np->v;
|
||||||
|
np->v = nv;
|
||||||
|
|
||||||
|
if (!np->last)
|
||||||
|
np->last= nv;
|
||||||
|
|
||||||
|
v = v->next;
|
||||||
|
if (v == p->v)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (v && np->last)
|
||||||
|
np->last->next = np->v;
|
||||||
|
return np;
|
||||||
|
}
|
44
poly2d/p2d_free.c
Normal file
44
poly2d/p2d_free.c
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* p2d_free.c - Deallocate polygons
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "poly2d.h"
|
||||||
|
|
||||||
|
|
||||||
|
void p2d_free(struct p2d *p)
|
||||||
|
{
|
||||||
|
struct v2d *v, *next;
|
||||||
|
|
||||||
|
v = p->v;
|
||||||
|
while (v) {
|
||||||
|
next = v->next;
|
||||||
|
free(v);
|
||||||
|
v = next;
|
||||||
|
if (v == p->v)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void p2d_free_all(struct p2d *p)
|
||||||
|
{
|
||||||
|
struct p2d *next;
|
||||||
|
|
||||||
|
while (p) {
|
||||||
|
next = p->next;
|
||||||
|
p2d_free(p);
|
||||||
|
p = next;
|
||||||
|
}
|
||||||
|
}
|
97
poly2d/p2d_gnuplot.c
Normal file
97
poly2d/p2d_gnuplot.c
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* p2d_gnuplot.c - File I/O in gnuplot format
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "poly2d.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define EPSILON 1e-6
|
||||||
|
|
||||||
|
|
||||||
|
static void check_closed(struct p2d *p)
|
||||||
|
{
|
||||||
|
if (!p)
|
||||||
|
return;
|
||||||
|
if (hypot(p->v->x-p->last->x, p->v->y-p->last->y) > EPSILON)
|
||||||
|
return;
|
||||||
|
free(p->last);
|
||||||
|
p->last = p->v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct p2d *p2d_read_gnuplot(FILE *file)
|
||||||
|
{
|
||||||
|
struct p2d *res = NULL, **last = &res, *p = NULL;
|
||||||
|
char buf[1024];
|
||||||
|
double x, y;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), file)) {
|
||||||
|
if (*buf == '#')
|
||||||
|
continue;
|
||||||
|
n = sscanf(buf, "%lf %lf\n", &x, &y);
|
||||||
|
switch (n) {
|
||||||
|
case -1:
|
||||||
|
check_closed(p);
|
||||||
|
p = NULL;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errno = EINVAL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!p) {
|
||||||
|
p = p2d_new();
|
||||||
|
*last = p;
|
||||||
|
last = &p->next;
|
||||||
|
}
|
||||||
|
p2d_append(p, v2d_new(x, y));
|
||||||
|
}
|
||||||
|
check_closed(p);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2d_write_gnuplot(FILE *file, const struct p2d *p)
|
||||||
|
{
|
||||||
|
const struct v2d *v;
|
||||||
|
|
||||||
|
v = p->v;
|
||||||
|
while (v) {
|
||||||
|
if (fprintf(file, "%g %g\n", v->x, v->y) < 0)
|
||||||
|
return 0;
|
||||||
|
v = v->next;
|
||||||
|
if (v == p->v) {
|
||||||
|
if (fprintf(file, "%g %g\n", v->x, v->y) < 0)
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fprintf(file, "\n") >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2d_write_gnuplot_all(FILE *file, const struct p2d *p)
|
||||||
|
{
|
||||||
|
while (p) {
|
||||||
|
if (!p2d_write_gnuplot(file, p))
|
||||||
|
return 0;
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
107
poly2d/p2d_hsort.c
Normal file
107
poly2d/p2d_hsort.c
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* p2d_hsort.c - Hierarchical polygon sort
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "poly2d.h"
|
||||||
|
#include "p2d_hsort.h"
|
||||||
|
|
||||||
|
|
||||||
|
static struct p2d_hier *recurse_hsort(struct p2d *p)
|
||||||
|
{
|
||||||
|
struct p2d *sub = NULL, *sub2 = NULL, **last = ⊂
|
||||||
|
struct p2d **a, *b, **next;
|
||||||
|
struct p2d_hier *res = NULL, *t;
|
||||||
|
struct p2d **res_last = (struct p2d **) &res;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move all polygons that are inside some other polygon to "sub".
|
||||||
|
*/
|
||||||
|
for (a = &p; *a; a = next) {
|
||||||
|
next = &(*a)->next;
|
||||||
|
for (b = p; b; b = b->next)
|
||||||
|
if (*a != b && p2d_contains_poly(b, *a)) {
|
||||||
|
*last = *a;
|
||||||
|
last = &(*last)->next;
|
||||||
|
*a = *next;
|
||||||
|
next = a;
|
||||||
|
*last = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (p) {
|
||||||
|
/*
|
||||||
|
* Begin transplanting "p" into t->p.
|
||||||
|
*/
|
||||||
|
t = alloc_type(struct p2d_hier);
|
||||||
|
t->p = *p;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move all polygons inside the current one from "sub" to
|
||||||
|
* "sub2". (Direct and indirect subordinates.)
|
||||||
|
*/
|
||||||
|
sub2 = NULL;
|
||||||
|
last = &sub2;
|
||||||
|
for (a = ⊂ *a; a = next) {
|
||||||
|
next = &(*a)->next;
|
||||||
|
if (p2d_contains_poly(p, *a)) {
|
||||||
|
*last = *a;
|
||||||
|
last = &(*last)->next;
|
||||||
|
*a = *next;
|
||||||
|
next = a;
|
||||||
|
*last = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sort the subordinates.
|
||||||
|
*/
|
||||||
|
t->holes = recurse_hsort(sub2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* End transplanting "p" into t->p.
|
||||||
|
*/
|
||||||
|
free(p);
|
||||||
|
p = t->p.next;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append "t" to "res".
|
||||||
|
*/
|
||||||
|
*res_last = &t->p;
|
||||||
|
res_last = &t->p.next;
|
||||||
|
t->p.next = NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct p2d_hier *p2d_hsort(const struct p2d *p)
|
||||||
|
{
|
||||||
|
return recurse_hsort(p2d_copy_all(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void p2d_hier_free(struct p2d_hier *t)
|
||||||
|
{
|
||||||
|
struct p2d_hier *next;
|
||||||
|
struct p2d *p;
|
||||||
|
|
||||||
|
while (t) {
|
||||||
|
p2d_hier_free(t->holes);
|
||||||
|
p = &t->p;
|
||||||
|
next = p2d_to_hier(p->next);
|
||||||
|
p2d_free_all(p);
|
||||||
|
t = next;
|
||||||
|
}
|
||||||
|
}
|
32
poly2d/p2d_hsort.h
Normal file
32
poly2d/p2d_hsort.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* p2d_hsort.h - Hierarchical polygon sort
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef P2D_HSORT_H
|
||||||
|
#define P2D_HSORT_H
|
||||||
|
|
||||||
|
#include "poly2d.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define p2d_to_hier(p) ((struct p2d_hier *) (p))
|
||||||
|
|
||||||
|
|
||||||
|
struct p2d_hier {
|
||||||
|
struct p2d p; /* "next" link for siblings */
|
||||||
|
struct p2d_hier *holes; /* children */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct p2d_hier *p2d_hsort(const struct p2d *p);
|
||||||
|
void p2d_hier_free(struct p2d_hier *t);
|
||||||
|
|
||||||
|
#endif /* !P2D_HSORT_H */
|
73
poly2d/p2d_make.c
Normal file
73
poly2d/p2d_make.c
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* p2d_make.c - Polygon creation
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "poly2d.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct p2d *p2d_new(void)
|
||||||
|
{
|
||||||
|
struct p2d *np;
|
||||||
|
|
||||||
|
np = alloc_type(struct p2d);
|
||||||
|
np->v = NULL;
|
||||||
|
np->last = NULL;
|
||||||
|
np->next = NULL;
|
||||||
|
return np;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct v2d *v2d_new(double x, double y)
|
||||||
|
{
|
||||||
|
struct v2d *nv;
|
||||||
|
|
||||||
|
nv = alloc_type(struct v2d);
|
||||||
|
nv->x = x;
|
||||||
|
nv->y = y;
|
||||||
|
nv->next = NULL;
|
||||||
|
return nv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void p2d_append(struct p2d *p, struct v2d *v)
|
||||||
|
{
|
||||||
|
if (p->last && p->last->next)
|
||||||
|
v->next = p->v;
|
||||||
|
if (p->last)
|
||||||
|
p->last->next = v;
|
||||||
|
else
|
||||||
|
p->v = v;
|
||||||
|
p->last = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void p2d_prepend(struct p2d *p, struct v2d *v)
|
||||||
|
{
|
||||||
|
v->next = p->v;
|
||||||
|
p->v = v;
|
||||||
|
if (p->last) {
|
||||||
|
if (p->last->next)
|
||||||
|
p->last->next = v;
|
||||||
|
} else {
|
||||||
|
p->last = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void p2d_close(struct p2d *p)
|
||||||
|
{
|
||||||
|
assert(!p->v || !p->last->next);
|
||||||
|
p->last->next = p->v;
|
||||||
|
}
|
78
poly2d/p2d_offset.cpp
Normal file
78
poly2d/p2d_offset.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* p2d_offset.cpp - Simple offsetting (without dogbones)
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 by Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* References:
|
||||||
|
* http://www.cgal.org/Manual/latest/examples/Straight_skeleton_2/
|
||||||
|
* Create_saop_from_polygon_with_holes_2.cpp
|
||||||
|
* http://www.cgal.org/Manual/latest/examples/Straight_skeleton_2/print.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "poly2d.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "cgal_helper.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Polygon_with_holes_2.h>
|
||||||
|
#include <CGAL/create_offset_polygons_from_polygon_with_holes_2.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||||
|
|
||||||
|
typedef CGAL::Polygon_2<K> Polygon_2;
|
||||||
|
typedef CGAL::Polygon_with_holes_2<K> Polygon_with_holes;
|
||||||
|
|
||||||
|
typedef boost::shared_ptr<Polygon_2> PolygonPtr;
|
||||||
|
|
||||||
|
typedef std::vector<PolygonPtr> PolygonPtrVector;
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" struct p2d *p2d_offset_holes(const struct p2d *p,
|
||||||
|
const struct p2d *holes, double off)
|
||||||
|
{
|
||||||
|
const struct p2d *h;
|
||||||
|
struct p2d *res = NULL, **last = &res;
|
||||||
|
|
||||||
|
assert(p2d_is_closed(p));
|
||||||
|
Polygon_with_holes poly(p2d_to_P2(p));
|
||||||
|
|
||||||
|
for (h = holes; h; h = h->next) {
|
||||||
|
assert(p2d_is_closed(h));
|
||||||
|
poly.add_hole(p2d_to_P2(h));
|
||||||
|
}
|
||||||
|
|
||||||
|
PolygonPtrVector tmp = off > 0 ?
|
||||||
|
CGAL::create_exterior_skeleton_and_offset_polygons_2(off,
|
||||||
|
poly.outer_boundary()) :
|
||||||
|
CGAL::create_interior_skeleton_and_offset_polygons_2(-off, poly);
|
||||||
|
|
||||||
|
for (PolygonPtrVector::const_iterator pit = tmp.begin();
|
||||||
|
pit != tmp.end(); ++pit) {
|
||||||
|
*last = P2_to_p2d(**pit);
|
||||||
|
last = &(*last)->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" struct p2d *p2d_offset(const struct p2d *p, double off)
|
||||||
|
{
|
||||||
|
return p2d_offset_holes(p, NULL, off);
|
||||||
|
}
|
140
poly2d/poly2d.h
Normal file
140
poly2d/poly2d.h
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* poly2d.h - The public face of the 2D Polygon library
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef POLY2D_H
|
||||||
|
#define POLY2D_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct v2d {
|
||||||
|
double x, y;
|
||||||
|
struct v2d *next; /* may end in NULL or may be cyclic */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct p2d {
|
||||||
|
struct v2d *v; /* vertices */
|
||||||
|
struct v2d *last; /* last vertex or vertex preceding first */
|
||||||
|
struct p2d *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Polygon creation
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct p2d *p2d_new(void);
|
||||||
|
struct v2d *v2d_new(double x, double y);
|
||||||
|
void p2d_append(struct p2d *p, struct v2d *v);
|
||||||
|
void p2d_prepend(struct p2d *p, struct v2d *v);
|
||||||
|
void p2d_close(struct p2d *p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Intersect line from A0 to A1 with line from B0 to B1.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 if the lines are parallel,
|
||||||
|
* 1 if the lines intersect between A0-A1 and B0-B1,
|
||||||
|
* -1 if the lines intersect outside A0-A1 or B0-B1.
|
||||||
|
*
|
||||||
|
* If v2d_intersect returns non-zero, the intersection P is at
|
||||||
|
*
|
||||||
|
* P = A0+(A1-A0)*na = B0+(B1-B0)*nb
|
||||||
|
*/
|
||||||
|
|
||||||
|
int v2d_intersect(const struct v2d *a0, const struct v2d *a1,
|
||||||
|
const struct v2d *b0, const struct v2d *b1,
|
||||||
|
double *na, double *nb);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the distance between point P and the line from A to B.
|
||||||
|
* The result is negative if P is on the "right" side of A->B.
|
||||||
|
*/
|
||||||
|
|
||||||
|
double v2d_line_distance(const struct v2d *a, const struct v2d *b,
|
||||||
|
const struct v2d *p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Duplicate a polygon
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct p2d *p2d_copy(const struct p2d *p);
|
||||||
|
struct p2d *p2d_copy_all(const struct p2d *p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Change a polygon from clockwise to counter-clockwise and vice versa.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct p2d *p2d_reverse(const struct p2d *p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* p2d_is_cw determine whether a polygon is clockwise.
|
||||||
|
* p2d_is_closed determines whether a polygon is closed.
|
||||||
|
* p2d_no_intersect determines whether a polygon does't self-intersect.
|
||||||
|
* p2d_vertices counts the number of vertices in a polygon.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int p2d_is_cw(const struct p2d *p);
|
||||||
|
int p2d_is_closed(const struct p2d *p);
|
||||||
|
int p2d_no_intersect(const struct p2d *p);
|
||||||
|
int p2d_vertices(const struct p2d *p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a possibly self-intersecting polygon into one or more simple
|
||||||
|
* polygons. [1]
|
||||||
|
*
|
||||||
|
* http://en.wikipedia.org/wiki/Simple_polygon
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct p2d *p2d_simplify(const struct p2d *p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* p2d_free deallocates a single polygon and its vertices.
|
||||||
|
* p2d_free_all deallocates all polygons in a list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void p2d_free(struct p2d *p);
|
||||||
|
void p2d_free_all(struct p2d *p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns non-zero if the point is inside or on the simple polygon.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int p2d_contains_point(const struct p2d *p, const struct v2d *v);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns:
|
||||||
|
* 0 if polygon "b" is outside of polygon "a"
|
||||||
|
* 1 if polygon "b" is inside of polygon "a"
|
||||||
|
* -1 if the two polygons intersect
|
||||||
|
*/
|
||||||
|
|
||||||
|
int p2d_contains_poly(const struct p2d *a, const struct p2d *b);
|
||||||
|
|
||||||
|
struct p2d *p2d_offset_holes(const struct p2d *p, const struct p2d *holes,
|
||||||
|
double off);
|
||||||
|
struct p2d *p2d_offset(const struct p2d *p, double off);
|
||||||
|
|
||||||
|
void p2d_area_holes_append(const struct p2d *p,
|
||||||
|
const struct p2d *holes, double offset, double overlap,
|
||||||
|
struct p2d ***last);
|
||||||
|
struct p2d *p2d_area_holes(const struct p2d *p, const struct p2d *holes,
|
||||||
|
double offset, double overlap);
|
||||||
|
struct p2d *p2d_area(const struct p2d *p, double offset, double overlap);
|
||||||
|
|
||||||
|
struct p2d *p2d_read_gnuplot(FILE *file);
|
||||||
|
int p2d_write_gnuplot(FILE *file, const struct p2d *p);
|
||||||
|
int p2d_write_gnuplot_all(FILE *file, const struct p2d *p);
|
||||||
|
|
||||||
|
#endif /* !POLY2D_H */
|
99
poly2d/test/Common
Executable file
99
poly2d/test/Common
Executable file
@ -0,0 +1,99 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Common - Elements shared by all regression tests for poly2d
|
||||||
|
#
|
||||||
|
# Written 2010, 2011 by Werner Almesberger
|
||||||
|
# Copyright 2010, 2011 Werner Almesberger
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
compile_and_run()
|
||||||
|
{
|
||||||
|
LIBS="-lpoly2d -lCGAL -lCGAL_Core -lboost_thread"
|
||||||
|
LIBS="$LIBS -lstdc++ -lmpfr -lgmp -lm"
|
||||||
|
|
||||||
|
cat <<EOF >_.c
|
||||||
|
#include <poly2d.h>
|
||||||
|
#include "p2d_hsort.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void recurse_hier(const struct p2d_hier *h, int level)
|
||||||
|
{
|
||||||
|
const struct v2d *v;
|
||||||
|
|
||||||
|
while (h) {
|
||||||
|
printf("%*s", level*2, "");
|
||||||
|
v = h->p.v;
|
||||||
|
while (v) {
|
||||||
|
printf("%s%g %g", v == h->p.v ? "" : " ", v->x, v->y);
|
||||||
|
v = v->next;
|
||||||
|
if (v == h->p.v)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
recurse_hier(h->holes, level+1);
|
||||||
|
h = p2d_to_hier(h->p.next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void __attribute__((unused)) print_hier(const struct p2d_hier *h)
|
||||||
|
{
|
||||||
|
recurse_hier(h, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
`cat _in`
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
gcc -Wall -Werror -g -I.. _.c -L.. $LIBS || return
|
||||||
|
$VALGRIND ./a.out
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tst()
|
||||||
|
{
|
||||||
|
echo -n "$1: " 1>&2
|
||||||
|
shift
|
||||||
|
cat >_in
|
||||||
|
compile_and_run "$@" >_out 2>&1 || {
|
||||||
|
echo FAILED "($SCRIPT)" 1>&2
|
||||||
|
cat _out
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tst_fail()
|
||||||
|
{
|
||||||
|
echo -n "$1: " 1>&2
|
||||||
|
shift
|
||||||
|
cat >_in
|
||||||
|
compile_and_run "$@" >_out 2>&1 && {
|
||||||
|
echo FAILED "($SCRIPT)" 1>&2
|
||||||
|
cat _out
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
rm -f _in _.c a.out
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
expect()
|
||||||
|
{
|
||||||
|
diff -u - "$@" _out >_diff || {
|
||||||
|
echo FAILED "($SCRIPT)" 1>&2
|
||||||
|
cat _diff 1>&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo PASSED 1>&2
|
||||||
|
rm -f _in _out _diff _.c a.out
|
||||||
|
passed=`expr ${passed:-0} + 1`
|
||||||
|
}
|
103
poly2d/test/area
Executable file
103
poly2d/test/area
Executable file
@ -0,0 +1,103 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. ./Common
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
tst "area without holes, constant offset" <<EOF
|
||||||
|
struct p2d *p = p2d_new();
|
||||||
|
struct p2d *q;
|
||||||
|
|
||||||
|
p2d_append(p, v2d_new(0, 0));
|
||||||
|
p2d_append(p, v2d_new(5.5, 0));
|
||||||
|
p2d_append(p, v2d_new(5.5, 4.5));
|
||||||
|
p2d_append(p, v2d_new(0, 4.5));
|
||||||
|
p2d_close(p);
|
||||||
|
q = p2d_area(p, 1, 0);
|
||||||
|
p2d_write_gnuplot_all(stdout, q);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
expect <<EOF
|
||||||
|
1 1
|
||||||
|
4.5 1
|
||||||
|
4.5 3.5
|
||||||
|
1 3.5
|
||||||
|
1 1
|
||||||
|
|
||||||
|
2 2
|
||||||
|
3.5 2
|
||||||
|
3.5 2.5
|
||||||
|
2 2.5
|
||||||
|
2 2
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
tst "area without holes, offset with overlap" <<EOF
|
||||||
|
struct p2d *p = p2d_new();
|
||||||
|
struct p2d *q;
|
||||||
|
|
||||||
|
p2d_append(p, v2d_new(0, 0));
|
||||||
|
p2d_append(p, v2d_new(5.5, 0));
|
||||||
|
p2d_append(p, v2d_new(5.5, 4.5));
|
||||||
|
p2d_append(p, v2d_new(0, 4.5));
|
||||||
|
p2d_close(p);
|
||||||
|
q = p2d_area(p, 1, 0.3);
|
||||||
|
p2d_write_gnuplot_all(stdout, q);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
expect <<EOF
|
||||||
|
1 1
|
||||||
|
4.5 1
|
||||||
|
4.5 3.5
|
||||||
|
1 3.5
|
||||||
|
1 1
|
||||||
|
|
||||||
|
1.7 1.7
|
||||||
|
3.8 1.7
|
||||||
|
3.8 2.8
|
||||||
|
1.7 2.8
|
||||||
|
1.7 1.7
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
tst "area with one symmetric hole" <<EOF
|
||||||
|
struct p2d *pl, *p;
|
||||||
|
struct p2d *q;
|
||||||
|
|
||||||
|
pl = p = p2d_new();
|
||||||
|
p2d_append(p, v2d_new(0, 0));
|
||||||
|
p2d_append(p, v2d_new(20, 0));
|
||||||
|
p2d_append(p, v2d_new(20, 10));
|
||||||
|
p2d_append(p, v2d_new(0, 10));
|
||||||
|
p2d_close(p);
|
||||||
|
|
||||||
|
p = p->next = p2d_new();
|
||||||
|
p2d_append(p, v2d_new(2, 2));
|
||||||
|
p2d_append(p, v2d_new(2, 8));
|
||||||
|
p2d_append(p, v2d_new(18, 8));
|
||||||
|
p2d_append(p, v2d_new(18, 2));
|
||||||
|
p2d_close(p);
|
||||||
|
|
||||||
|
q = p2d_area(pl, 0.7, 0);
|
||||||
|
p2d_write_gnuplot_all(stdout, q);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
expect <<EOF
|
||||||
|
0.7 0.7
|
||||||
|
19.3 0.7
|
||||||
|
19.3 9.3
|
||||||
|
0.7 9.3
|
||||||
|
0.7 0.7
|
||||||
|
|
||||||
|
1.3 1.3
|
||||||
|
1.3 8.7
|
||||||
|
18.7 8.7
|
||||||
|
18.7 1.3
|
||||||
|
1.3 1.3
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
96
poly2d/test/hsort
Executable file
96
poly2d/test/hsort
Executable file
@ -0,0 +1,96 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. ./Common
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
tst "hierarchical sort with one hole" <<EOF
|
||||||
|
struct p2d *pl, *p;
|
||||||
|
|
||||||
|
pl = p = p2d_new();
|
||||||
|
p2d_append(p, v2d_new(0, 0));
|
||||||
|
p2d_append(p, v2d_new(20, 0));
|
||||||
|
p2d_append(p, v2d_new(20, 10));
|
||||||
|
p2d_append(p, v2d_new(0, 10));
|
||||||
|
p2d_close(p);
|
||||||
|
|
||||||
|
p = p->next = p2d_new();
|
||||||
|
p2d_append(p, v2d_new(2, 2));
|
||||||
|
p2d_append(p, v2d_new(2, 8));
|
||||||
|
p2d_append(p, v2d_new(18, 8));
|
||||||
|
p2d_append(p, v2d_new(18, 2));
|
||||||
|
p2d_close(p);
|
||||||
|
|
||||||
|
print_hier(p2d_hsort(pl));
|
||||||
|
EOF
|
||||||
|
|
||||||
|
expect <<EOF
|
||||||
|
0 0 20 0 20 10 0 10
|
||||||
|
2 2 2 8 18 8 18 2
|
||||||
|
EOF
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
tst "hierarchical sort with two holes" <<EOF
|
||||||
|
struct p2d *pl, *p;
|
||||||
|
|
||||||
|
pl = p = p2d_new();
|
||||||
|
p2d_append(p, v2d_new(0, 0));
|
||||||
|
p2d_append(p, v2d_new(10, 0));
|
||||||
|
p2d_append(p, v2d_new(10, 10));
|
||||||
|
p2d_close(p);
|
||||||
|
|
||||||
|
p = p->next = p2d_new();
|
||||||
|
p2d_append(p, v2d_new(2, 2));
|
||||||
|
p2d_append(p, v2d_new(4, 2));
|
||||||
|
p2d_append(p, v2d_new(4, 4));
|
||||||
|
p2d_close(p);
|
||||||
|
|
||||||
|
p = p->next = p2d_new();
|
||||||
|
p2d_append(p, v2d_new(6, 2));
|
||||||
|
p2d_append(p, v2d_new(8, 2));
|
||||||
|
p2d_append(p, v2d_new(8, 8));
|
||||||
|
p2d_close(p);
|
||||||
|
|
||||||
|
print_hier(p2d_hsort(pl));
|
||||||
|
EOF
|
||||||
|
|
||||||
|
expect <<EOF
|
||||||
|
0 0 10 0 10 10
|
||||||
|
2 2 4 2 4 4
|
||||||
|
6 2 8 2 8 8
|
||||||
|
EOF
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
tst "hierarchical sort with nested holes" <<EOF
|
||||||
|
struct p2d *pl, *p;
|
||||||
|
|
||||||
|
pl = p = p2d_new();
|
||||||
|
p2d_append(p, v2d_new(0, 0));
|
||||||
|
p2d_append(p, v2d_new(10, 0));
|
||||||
|
p2d_append(p, v2d_new(10, 10));
|
||||||
|
p2d_close(p);
|
||||||
|
|
||||||
|
p = p->next = p2d_new();
|
||||||
|
p2d_append(p, v2d_new(2, 2));
|
||||||
|
p2d_append(p, v2d_new(8, 2));
|
||||||
|
p2d_append(p, v2d_new(8, 8));
|
||||||
|
p2d_close(p);
|
||||||
|
|
||||||
|
p = p->next = p2d_new();
|
||||||
|
p2d_append(p, v2d_new(3, 3));
|
||||||
|
p2d_append(p, v2d_new(7, 3));
|
||||||
|
p2d_append(p, v2d_new(7, 7));
|
||||||
|
p2d_close(p);
|
||||||
|
|
||||||
|
print_hier(p2d_hsort(pl));
|
||||||
|
EOF
|
||||||
|
|
||||||
|
expect <<EOF
|
||||||
|
0 0 10 0 10 10
|
||||||
|
2 2 8 2 8 8
|
||||||
|
3 3 7 3 7 7
|
||||||
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
61
poly2d/test/make
Executable file
61
poly2d/test/make
Executable file
@ -0,0 +1,61 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. ./Common
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
tst "make an open polygon" <<EOF
|
||||||
|
struct p2d *p = p2d_new();
|
||||||
|
|
||||||
|
p2d_append(p, v2d_new(0, 0));
|
||||||
|
p2d_append(p, v2d_new(1, 2));
|
||||||
|
p2d_write_gnuplot(stdout, p);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
expect <<EOF
|
||||||
|
0 0
|
||||||
|
1 2
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
tst "make a closed polygon" <<EOF
|
||||||
|
struct p2d *p = p2d_new();
|
||||||
|
|
||||||
|
p2d_append(p, v2d_new(-1, 1));
|
||||||
|
p2d_append(p, v2d_new(3, 7));
|
||||||
|
p2d_close(p);
|
||||||
|
p2d_write_gnuplot(stdout, p);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
expect <<EOF
|
||||||
|
-1 1
|
||||||
|
3 7
|
||||||
|
-1 1
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
tst "make two open polygons" <<EOF
|
||||||
|
struct p2d *p = p2d_new();
|
||||||
|
struct p2d *q = p2d_new();
|
||||||
|
|
||||||
|
p2d_append(p, v2d_new(1, 4));
|
||||||
|
p2d_append(p, v2d_new(2, 8));
|
||||||
|
p->next = q;
|
||||||
|
p2d_append(q, v2d_new(3, 15));
|
||||||
|
p2d_append(q, v2d_new(4, 16));
|
||||||
|
p2d_write_gnuplot_all(stdout, p);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
expect <<EOF
|
||||||
|
1 4
|
||||||
|
2 8
|
||||||
|
|
||||||
|
3 15
|
||||||
|
4 16
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
52
poly2d/test/offset
Executable file
52
poly2d/test/offset
Executable file
@ -0,0 +1,52 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. ./Common
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
tst "outer offset" <<EOF
|
||||||
|
struct p2d *p = p2d_new();
|
||||||
|
struct p2d *q;
|
||||||
|
|
||||||
|
p2d_append(p, v2d_new(0, 0));
|
||||||
|
p2d_append(p, v2d_new(2, 0));
|
||||||
|
p2d_append(p, v2d_new(2, 1));
|
||||||
|
p2d_append(p, v2d_new(0, 1));
|
||||||
|
p2d_close(p);
|
||||||
|
q = p2d_offset(p, 0.5);
|
||||||
|
p2d_write_gnuplot(stdout, p2d_reverse(q->next));
|
||||||
|
EOF
|
||||||
|
|
||||||
|
expect <<EOF
|
||||||
|
-0.5 -0.5
|
||||||
|
2.5 -0.5
|
||||||
|
2.5 1.5
|
||||||
|
-0.5 1.5
|
||||||
|
-0.5 -0.5
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
tst "inner offset" <<EOF
|
||||||
|
struct p2d *p = p2d_new();
|
||||||
|
struct p2d *q;
|
||||||
|
|
||||||
|
p2d_append(p, v2d_new(0, 0));
|
||||||
|
p2d_append(p, v2d_new(2, 0));
|
||||||
|
p2d_append(p, v2d_new(2, 1));
|
||||||
|
p2d_append(p, v2d_new(0, 1));
|
||||||
|
p2d_close(p);
|
||||||
|
q = p2d_offset(p, -0.1);
|
||||||
|
p2d_write_gnuplot(stdout, q);
|
||||||
|
EOF
|
||||||
|
|
||||||
|
expect <<EOF
|
||||||
|
0.1 0.1
|
||||||
|
1.9 0.1
|
||||||
|
1.9 0.9
|
||||||
|
0.1 0.9
|
||||||
|
0.1 0.1
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
28
poly2d/util.h
Normal file
28
poly2d/util.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* util.h - Common utility functions
|
||||||
|
*
|
||||||
|
* Written 2009 by Werner Almesberger
|
||||||
|
* Copyright 2009 by Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UTIL_H
|
||||||
|
#define UTIL_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define alloc_size(s) \
|
||||||
|
({ void *alloc_size_tmp = malloc(s); \
|
||||||
|
if (!alloc_size_tmp) \
|
||||||
|
abort(); \
|
||||||
|
alloc_size_tmp; })
|
||||||
|
|
||||||
|
#define alloc_type(t) ((t *) alloc_size(sizeof(t)))
|
||||||
|
|
||||||
|
#endif /* !UTIL_H */
|
69
poly2d/v2d_intersect.c
Normal file
69
poly2d/v2d_intersect.c
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* v2d_intersect.c - Intersect two lines
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "poly2d.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define EPSILON 1e-6
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Solve
|
||||||
|
*
|
||||||
|
* ax+by = e
|
||||||
|
* cx+dy = f
|
||||||
|
*
|
||||||
|
* with Cramer's rule:
|
||||||
|
* http://en.wikipedia.org/wiki/Cramer's_rule
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int cramer2(double a, double b, double c, double d, double e, double f,
|
||||||
|
double *x, double *y)
|
||||||
|
{
|
||||||
|
double det;
|
||||||
|
|
||||||
|
det = a*d-b*c;
|
||||||
|
if (fabs(det) < EPSILON)
|
||||||
|
return 0;
|
||||||
|
*x = (e*d-b*f)/det;
|
||||||
|
*y = (a*f-e*c)/det;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int v2d_intersect(const struct v2d *a0, const struct v2d *a1,
|
||||||
|
const struct v2d *b0, const struct v2d *b1,
|
||||||
|
double *na, double *nb)
|
||||||
|
{
|
||||||
|
double ax, ay, bx, by, dx, dy;
|
||||||
|
double a, b;
|
||||||
|
|
||||||
|
ax = a1->x-a0->x;
|
||||||
|
ay = a1->y-a0->y;
|
||||||
|
|
||||||
|
bx = b1->x-b0->x;
|
||||||
|
by = b1->y-b0->y;
|
||||||
|
|
||||||
|
dx = b0->x-a0->x;
|
||||||
|
dy = b0->y-a0->y;
|
||||||
|
|
||||||
|
if (!cramer2(ax, -bx, ay, -by, dx, dy, &a, &b))
|
||||||
|
return 0;
|
||||||
|
if (na)
|
||||||
|
*na = a;
|
||||||
|
if (nb)
|
||||||
|
*nb = b;
|
||||||
|
return a >= 0 && a <= 1 && b >= 0 && b <= 1 ? 1 : -1;
|
||||||
|
}
|
34
poly2d/v2d_line_distance.c
Normal file
34
poly2d/v2d_line_distance.c
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* v2d_line_distance.c - Calculate the distance between a point and a line
|
||||||
|
*
|
||||||
|
* Written 2012 by Werner Almesberger
|
||||||
|
* Copyright 2012 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "poly2d.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use formula (14) from
|
||||||
|
* http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
|
||||||
|
* but keep the sign.
|
||||||
|
*/
|
||||||
|
|
||||||
|
double v2d_line_distance(const struct v2d *a, const struct v2d *b,
|
||||||
|
const struct v2d *p)
|
||||||
|
{
|
||||||
|
double ax, ay;
|
||||||
|
|
||||||
|
ax = b->x-a->x;
|
||||||
|
ay = b->y-a->y;
|
||||||
|
|
||||||
|
return (ax*(a->y-p->y)-ay*(a->x-p->x))/hypot(ax, ay);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user