├── configure.win ├── src ├── Makevars.win ├── clipper.cpp ├── Makevars ├── Makevars.in ├── clipper.h └── interface.cpp ├── cleanup ├── .gitattributes ├── .Rbuildignore ├── NAMESPACE ├── .gitignore ├── R ├── First.R └── clipper.R ├── DESCRIPTION ├── appveyor.yml ├── .travis.yml ├── README.md ├── man ├── polyminkowski.Rd ├── polysimplify.Rd ├── polyoffset.Rd ├── polyclip.Rd └── polylineoffset.Rd ├── configure.ac ├── config.log └── config.status /configure.win: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Makevars.win: -------------------------------------------------------------------------------- 1 | PKG_CPPFLAGS = 2 | -------------------------------------------------------------------------------- /cleanup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -f config.* src/Makevars 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | data/* binary 3 | src/* text=lf 4 | R/* text=lf 5 | -------------------------------------------------------------------------------- /src/clipper.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacamp/polyclip/master/src/clipper.cpp -------------------------------------------------------------------------------- /src/Makevars: -------------------------------------------------------------------------------- 1 | PKG_CPPFLAGS = -DPOLYCLIP_LONG64="int64_t" -DPOLYCLIP_ULONG64="uint64_t" 2 | -------------------------------------------------------------------------------- /src/Makevars.in: -------------------------------------------------------------------------------- 1 | PKG_CPPFLAGS = @POLYCLIP_CPPFLAGS@ 2 | PKG_CXXFLAGS = @POLYCLIP_CXXFLAGS@ 3 | @POLYCLIP_CXX_DECLAR@ 4 | 5 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | README.md 2 | ^.*\.Rproj$ 3 | ^\.Rproj\.user$ 4 | ^\.travis\.yml$ 5 | \.gcov$ 6 | \.gcda$ 7 | \.gcno$ 8 | ^appveyor\.yml$ 9 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | export(polyclip,polyoffset,polylineoffset,polysimplify,polyminkowski) 2 | useDynLib(polyclip, 3 | "Cclipbool","Cpolyoffset","Clineoffset","Csimplify","Cminksum") 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Emacs backups 2 | *~ 3 | 4 | # History files 5 | .Rhistory 6 | 7 | # Example code in package build process 8 | *-Ex.R 9 | 10 | # R data files from past sessions 11 | .Rdata 12 | .Rproj.user 13 | 14 | # R-studio files 15 | polyclip.Rproj 16 | 17 | # covr files 18 | src/*.gcov 19 | src/*.gcda 20 | src/*.gcno 21 | 22 | # .o files 23 | src/*o -------------------------------------------------------------------------------- /R/First.R: -------------------------------------------------------------------------------- 1 | # First.R 2 | # 3 | # $Revision: 1.1 $ $Date: 2013/10/19 03:06:59 $ 4 | # 5 | 6 | .onLoad <- function(...) {} 7 | 8 | .onAttach <- function(libname, pkgname) { 9 | dfile <- system.file("DESCRIPTION", package="polyclip") 10 | ver <- read.dcf(file=dfile, fields="Version") 11 | clipperbuild <- read.dcf(file=dfile, fields="Note") 12 | msg <- paste("polyclip", ver, clipperbuild) 13 | packageStartupMessage(msg) 14 | invisible(NULL) 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: polyclip 2 | Version: 1.5-6 3 | Date: 2016-04-02 4 | Title: Polygon Clipping 5 | Authors@R: c(person("Angus", "Johnson", role = "aut", 6 | comment="C++ original, http://www.angusj.com/delphi/clipper.php"), 7 | person("Adrian", "Baddeley", role = c("aut", "trl", "cre"), 8 | email = "Adrian.Baddeley@curtin.edu.au"), 9 | person(c("Brian", "D."), "Ripley", role = "ctb")) 10 | Maintainer: Adrian Baddeley 11 | Depends: R (>= 3.0.0) 12 | Description: R port of Angus Johnson's open source library Clipper. Performs polygon clipping operations (intersection, union, set minus, set difference) for polygonal regions of arbitrary complexity, including holes. Computes offset polygons (spatial buffer zones, morphological dilations, Minkowski dilations) for polygonal regions and polygonal lines. Computes Minkowski Sum of general polygons. There is a function for removing self-intersections from polygon data. 13 | License: BSL 14 | URL: http://www.angusj.com/delphi/clipper.php, https://sourceforge.net/projects/polyclipping, https://github.com/baddstats/polyclip 15 | LazyData: true 16 | LazyLoad: true 17 | ByteCompile: true 18 | Note: built from Clipper C++ version 6.4.0 19 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # DO NOT CHANGE the "init" and "install" sections below 2 | 3 | # Download script file from GitHub 4 | init: 5 | ps: | 6 | $ErrorActionPreference = "Stop" 7 | Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1" 8 | Import-Module '..\appveyor-tool.ps1' 9 | 10 | install: 11 | ps: Bootstrap 12 | 13 | # Adapt as necessary starting from here 14 | 15 | environment: 16 | global: 17 | WARNINGS_ARE_ERRORS: 1 18 | access_token: 19 | secure: GCPohlv0NVqq0Cv3wh0Luw1OgO3jS4hyU7zUkA4a/TPMsqq1mYSm0/8Qb3uPrR7d 20 | 21 | build_script: 22 | - travis-tool.sh install_deps 23 | 24 | test_script: 25 | - travis-tool.sh run_tests 26 | 27 | on_failure: 28 | - 7z a failure.zip *.Rcheck\* 29 | - appveyor PushArtifact failure.zip 30 | 31 | artifacts: 32 | - path: '*.Rcheck\**\*.log' 33 | name: Logs 34 | 35 | - path: '*.Rcheck\**\*.out' 36 | name: Logs 37 | 38 | - path: '*.Rcheck\**\*.fail' 39 | name: Logs 40 | 41 | - path: '*.Rcheck\**\*.Rout' 42 | name: Logs 43 | 44 | - path: '\*_*.tar.gz' 45 | name: Bits 46 | 47 | - path: '\*_*.zip' 48 | name: Bits 49 | 50 | deploy: 51 | provider: GitHub 52 | auth_token: 53 | secure: TAti5R3iqVWn6zyRuWY/0YbgmJs+5M2Ipync4rs9UdyszqOtK7gzgCS1yWCJIrMK 54 | artifact: /\*_*.zip/ 55 | on: 56 | branch: 57 | - master 58 | - /v\d\.\d-\d/ 59 | appveyor_repo_tag: true 60 | 61 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: r 2 | r: 3 | - release 4 | - devel 5 | sudo: false 6 | cache: packages 7 | os: 8 | - linux 9 | - osx 10 | r_github_packages: 11 | - jimhester/covr 12 | after_success: 13 | - if [[ "$TRAVIS_R_VERSION" != "devel" && ("$TRAVIS_OS_NAME" == "osx") ]]; then R CMD INSTALL --build $PKG_TARBALL; fi 14 | - if [[ "$TRAVIS_R_VERSION" != "devel" && ("$TRAVIS_OS_NAME" == "linux") ]]; then R CMD INSTALL $PKG_TARBALL; fi 15 | - if [[ "$TRAVIS_R_VERSION" != "devel" && ("$TRAVIS_OS_NAME" == "linux") ]]; then Rscript -e 'covr::codecov(type = "examples")'; fi 16 | deploy: 17 | provider: releases 18 | api_key: 19 | secure: qau8PJIhPE6JlM+2mhGPuacL6MjUMd9HITKGUoXUwLBbtHKsYDYwLRWnqLDnsexOUeZm/dWHpixPD8TxKIrkT1P59jRkHKhC0k0tgs6NMB+JjRRFGzFp6m0DSkpei/6/F6owR9lWXyqxL8j+ownzBNiTtX356yr+XcLBZz/yxNJYD7FjLA0NDjoAEY92vmczNZRXJcjq9i3gehok3PHvybBZvi+sXvjorvLbewy36DRypA7TpAmgwqOi4Flxzbb8VFO6AsPwydZtI3PCpnd9KcaQ3uirb1De5Q1PWNIENdzLCGl9A9LOAKiMLa4k8KrhbmynBihvUisSwhoLEF0GI2qB4P191KOAjsEM9uWHrX3UqvlatGA/bhDtqwjoDyHeXSGv7USerk6CFzk2+kh67yCOZGg5HFB62lMxxXWzxMEfw9kisXV+aL7zeZjfsXHJ1sXlvAsEx2sk6NIYGSkQJcUbKL6UhJ15EJw1X33c3xfzFh66QzUELJ0bkVm5hFLvLPtcKGSU2NmLQArIYJbCf1rcXkjHQDl0IBYWK4dBXU27kckSiCWV71NMDIGUSV6SuGaPGCyRH6trmSjNdmMCh/5zOo8MBvm/D8y/yUrkj+qkQ7+XUSPFfL7xHzakrdlHE39L35IFIhiKzNTwy3LWblupYHStN81TgANwMVJc1gc= 20 | skip_cleanup: true 21 | file_glob: true 22 | file: polyclip_*.t*gz 23 | on: 24 | tags: true 25 | condition: "$TRAVIS_R_VERSION != devel && ($TRAVIS_OS_NAME == osx)" 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | polyclip 2 | ======== 3 | 4 | [![Travis-CI Build Status](https://travis-ci.org/baddstats/polyclip.png?branch=master)](https://travis-ci.org/baddstats/polyclip) 5 | [![codecov.io](https://codecov.io/github/baddstats/polyclip/coverage.svg?branch=master)](https://codecov.io/github/baddstats/polyclip?branch=master) 6 | [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/polyclip)](http://cran.r-project.org/web/packages/polyclip) 7 | [![Research software impact](http://depsy.org/api/package/cran/polyclip/badge.svg)](http://depsy.org/package/r/polyclip) 8 | 9 | This repository holds the contributed R-package `polyclip`, which is 10 | an R port of Angus Johnson's library 11 | [Clipper](http://angusj.com/delphi/clipper.php) for polygon clipping. 12 | 13 | ## Version 14 | 15 | This version of `polyclip` is derived from 16 | Clipper C++ library version `6.4.0 [r496]` which was obtained from the 17 | [Sourceforge repository](https://sourceforge.net/projects/polyclipping) 18 | (click `Code` then `Download snapshot`). 19 | Minor changes have been made to the C++ code to satisfy the 20 | requirements for R packages (namely, data type declarations must be portable, 21 | and error messages must go through R's error handler). 22 | 23 | ## Installation 24 | 25 | The current official release of `polyclip` is available 26 | on [CRAN](http://cran.r-project.org/web/packages/polyclip) 27 | and can be downloaded and installed automatically 28 | using the R command `install.packages`. 29 | 30 | The code in this repository is the development version, 31 | which may be newer than the official release. 32 | The easiest way to install the development version of `polyclip` 33 | from github is through the `devtools` package: 34 | 35 | ```R 36 | require(devtools) 37 | install_github('baddstats/polyclip') 38 | ``` 39 | 40 | If you don't have `devtools` installed you should first run 41 | 42 | ```R 43 | install.packages('devtools') 44 | ``` 45 | 46 | ## Bug reports 47 | 48 | Users of `polyclip` are encouraged to report bugs here 49 | (go to *issues* in the menu above, 50 | and press *new issue* to start a new bug report 51 | or feature request). 52 | 53 | ## Making your own changes 54 | 55 | Feel free to fork `polyclip`, make changes to the code, 56 | and ask us to include them in the package by making a github *pull request*. 57 | 58 | -------------------------------------------------------------------------------- /man/polyminkowski.Rd: -------------------------------------------------------------------------------- 1 | \name{polyminkowski} 2 | \alias{polyminkowski} 3 | \title{ 4 | Minkowski Sum of Polygon with Path 5 | } 6 | \description{ 7 | Compute the Minkowski Sum of a polygon with 8 | a path or paths. 9 | } 10 | \usage{ 11 | polyminkowski(A, B, \dots, eps, x0, y0, 12 | closed=TRUE) 13 | } 14 | \arguments{ 15 | \item{A}{ 16 | Data specifying a polygon or polygons. See Details. 17 | } 18 | \item{B}{ 19 | Data specifying a path or paths. See Details. 20 | } 21 | \item{\dots}{ 22 | Ignored. 23 | } 24 | \item{eps}{Spatial resolution for coordinates.} 25 | \item{x0,y0}{Spatial origin for coordinates.} 26 | \item{closed}{ 27 | Logical value indicating whether the resulting path 28 | should be interpreted as closed (last vertex joined to first vertex 29 | and interior filled in). 30 | } 31 | } 32 | \details{ 33 | This is an interface to the function \code{MinkowskiSum} in 34 | Angus Johnson's \code{C++} library \pkg{Clipper}. 35 | 36 | It computes the Minkowski Sum of the polygon \code{A} 37 | (including its interior) with the path or paths \code{B} 38 | (\emph{excluding} their interior). 39 | 40 | The argument \code{A} should be 41 | a list containing two components \code{x} and \code{y} 42 | giving the coordinates of the vertices of a single polygon. 43 | The last vertex should 44 | not repeat the first vertex. 45 | 46 | The argument \code{B} should be either 47 | \itemize{ 48 | \item 49 | a list containing two components \code{x} and \code{y} 50 | giving the coordinates of the vertices of a single polygon or path. 51 | The last vertex should 52 | not repeat the first vertex. 53 | \item 54 | a \code{list} of \code{list(x,y)} structures giving 55 | the coordinates of the vertices of several polygons or paths. 56 | } 57 | 58 | \bold{Calculations are performed in integer arithmetic} 59 | after subtracting \code{x0,y0} from the coordinates, 60 | dividing by \code{eps}, and rounding to the nearest integer. 61 | Thus, \code{eps} is the effective spatial resolution. 62 | The default values ensure reasonable accuracy. 63 | } 64 | \value{ 65 | Data specifying polygons, in the same format as \code{A}. 66 | } 67 | \author{Angus Johnson. 68 | Ported to \R by Adrian Baddeley 69 | \email{Adrian.Baddeley@curtin.edu.au}. 70 | } 71 | \references{ 72 | Clipper Website: \url{http://www.angusj.com} 73 | } 74 | \seealso{ 75 | \code{\link{polyclip}}, 76 | \code{\link{polyoffset}}, 77 | \code{\link{polylineoffset}}, 78 | \code{\link{polysimplify}} 79 | } 80 | \examples{ 81 | A <- list(list(x=c(-3,3,3,-3),y=c(-3,-3,3,3))) 82 | B <- list(list(x=c(-1,1,1,-1),y=c(-1,-1,1,1))) 83 | C <- polyminkowski(A, B) 84 | opa <- par(mfrow=c(1,3)) 85 | rr <- c(-4, 4) 86 | plot(rr, rr, type="n", axes=FALSE, xlab="", ylab="", main="A") 87 | polygon(A[[1]], col="blue") 88 | plot(rr,rr, type="n", axes=FALSE, xlab="", ylab="", main="B") 89 | polygon(B[[1]], border="red", lwd=4) 90 | plot(rr,rr, type="n", axes=FALSE, xlab="", ylab="", main="A+B") 91 | polygon(C[[1]], col="green") 92 | polygon(C[[2]], col="white") 93 | par(opa) 94 | } 95 | \keyword{spatial} 96 | \keyword{manip} 97 | 98 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(polyclip,[1.5-4]) 2 | AC_PROG_CXX 3 | AC_LANG([C++]) 4 | dnl Check for presence of C++11 5 | CXX1X=`"${R_HOME}/bin/R" CMD config CXX1X` 6 | if test "${CXX1X}" != ""; then 7 | echo "compiling under C++11" 8 | CXX1XSTD=`"${R_HOME}/bin/R" CMD config CXX1XSTD` 9 | CXX="${CXX1X} ${CXX1XSTD}" 10 | POLYCLIP_CXX_DECLAR="CXX_STD = CXX11" 11 | CXXFLAGS=`"${R_HOME}/bin/R" CMD config CXX1XFLAGS` 12 | else 13 | echo "C++11 is not supported; compiling under vanilla C++" 14 | CXX=`"${R_HOME}/bin/R" CMD config CXX` 15 | POLYCLIP_CXX_DECLAR="" 16 | CXXFLAGS=`"${R_HOME}/bin/R" CMD config CXXFLAGS` 17 | fi 18 | CPPFLAGS=`"${R_HOME}/bin/R" CMD config CPPFLAGS` 19 | dnl Check for availability of 64-bit integer types in C++ 20 | dnl Signed 64-bit integer 21 | long64="" 22 | name64="signed 64-bit integers (cInt)" 23 | if test "${CXX1X}" != ""; then 24 | long64="signed long long" 25 | POLYCLIP_LONG64="${long64}" 26 | else 27 | AC_CHECK_TYPES([int64_t],[long64="int64_t"],[],[#include ]) 28 | if test "${long64}" != ""; then 29 | POLYCLIP_LONG64="${long64}" 30 | else 31 | AC_CHECK_TYPES([int_fast64_t],[long64="int_fast64_t"],[],[#include ]) 32 | if test "${long64}" != ""; then 33 | POLYCLIP_LONG64="${long64}" 34 | else 35 | AC_CHECK_TYPES([int_least64_t],[long64="int_least64_t"],[],[#include ]) 36 | if test "${long64}" != ""; then 37 | POLYCLIP_LONG64="${long64}" 38 | else 39 | AC_CHECK_TYPES([long long],[long64="long long"]) 40 | if test "${long64}" != ""; then 41 | POLYCLIP_LONG64="${long64}" 42 | else 43 | echo "Error: unable to find a C++ data type for ${name64}" 44 | exit 1 45 | fi 46 | fi 47 | fi 48 | fi 49 | fi 50 | echo " In src/clipper.h, ${name64}" 51 | echo " will be declared as '${long64}'" 52 | dnl Unsigned 64-bit integer 53 | ulong64="" 54 | uname64="unsigned 64-bit integers (cUInt)" 55 | if test "${CXX1X}" != ""; then 56 | ulong64="unsigned long long" 57 | POLYCLIP_ULONG64="${ulong64}" 58 | else 59 | AC_CHECK_TYPES([uint64_t],[ulong64="uint64_t"],[],[#include ]) 60 | if test "${ulong64}" != ""; then 61 | POLYCLIP_ULONG64="${ulong64}" 62 | else 63 | AC_CHECK_TYPES([uint_fast64_t],[ulong64="uint_fast64_t"],[],[#include ]) 64 | if test "${ulong64}" != ""; then 65 | POLYCLIP_ULONG64="${ulong64}" 66 | else 67 | AC_CHECK_TYPES([uint_least64_t],[ulong64="uint_least64_t"],[],[#include ]) 68 | if test "${ulong64}" != ""; then 69 | POLYCLIP_ULONG64="${ulong64}" 70 | else 71 | AC_CHECK_TYPES([unsigned long long],[ulong64="unsigned long long"]) 72 | if test "${ulong64}" != ""; then 73 | POLYCLIP_ULONG64="${ulong64}" 74 | else 75 | echo "Error: unable to find a C++ data type for ${uname64}" 76 | exit 1 77 | fi 78 | fi 79 | fi 80 | fi 81 | fi 82 | echo " In src/clipper.h, ${uname64}" 83 | echo " will be declared as '${ulong64}'" 84 | dnl Put results in C++ preprocessor flags 85 | POLYCLIP_CPPFLAGS="-DPOLYCLIP_LONG64=\"${POLYCLIP_LONG64}\" -DPOLYCLIP_ULONG64=\"${POLYCLIP_ULONG64}\"" 86 | POLYCLIP_CXXFLAGS="${CXXFLAGS}" 87 | AC_SUBST(POLYCLIP_CPPFLAGS) 88 | AC_SUBST(POLYCLIP_CXXFLAGS) 89 | AC_SUBST(POLYCLIP_CXX_DECLAR) 90 | AC_CONFIG_FILES([src/Makevars]) 91 | AC_OUTPUT 92 | 93 | 94 | -------------------------------------------------------------------------------- /man/polysimplify.Rd: -------------------------------------------------------------------------------- 1 | \name{polysimplify} 2 | \alias{polysimplify} 3 | \title{ 4 | Remove Self-Intersections from a Polygon 5 | } 6 | \description{ 7 | This function attempts to remove self-intersections and duplicated 8 | vertices from the given polygon. 9 | } 10 | \usage{ 11 | polysimplify(A, \dots, eps, x0, y0, 12 | filltype = c("evenodd", "nonzero", "positive", "negative")) 13 | } 14 | \arguments{ 15 | \item{A}{ 16 | Data specifying a polygon or polygons. See Details. 17 | } 18 | \item{\dots}{ 19 | Ignored. 20 | } 21 | \item{eps}{Spatial resolution for coordinates.} 22 | \item{x0,y0}{Spatial origin for coordinates.} 23 | \item{filltype}{Polygon-filling rule. See Details.} 24 | } 25 | \details{ 26 | This is an interface to the function \code{SimplifyPolygons} in 27 | Angus Johnson's \code{C++} library \pkg{Clipper}. 28 | It tries to remove self-intersections from the supplied polygon, 29 | by performing a boolean union operation using the nominated 30 | \code{filltype}. The result may be one or several polygons. 31 | 32 | The argument \code{A} should be either 33 | \itemize{ 34 | \item 35 | a list containing two components \code{x} and \code{y} 36 | giving the coordinates of the vertices of a single polygon. 37 | The last vertex should 38 | not repeat the first vertex. 39 | \item 40 | a \code{list} of \code{list(x,y)} structures giving 41 | the coordinates of the vertices of several polygons. 42 | } 43 | 44 | The argument \code{filltype} determines the polygon fill type. 45 | \describe{ 46 | \item{Even-Odd:}{ 47 | The default rule is \emph{even-odd} filling, 48 | in which every polygon edge demarcates a boundary between 49 | the inside and outside of the region. 50 | It does not matter whether a polygon is traversed in 51 | clockwise or anticlockwise order. Holes are determined 52 | simply by their locations relative to other polygons such that 53 | outers contain holes and holes contain outers. 54 | } 55 | \item{Non-Zero:}{ 56 | Under the \emph{nonzero} filling rule, an outer boundary must be 57 | traversed in clockwise order, while a hole must be traversed 58 | in anticlockwise order. 59 | } 60 | \item{Positive:}{ 61 | Under the \code{positive} filling rule, the filled region 62 | consists of all points with positive winding number. 63 | } 64 | \item{Negative:}{ 65 | Under the \code{negative} filling rule, the filled region 66 | consists of all points with negative winding number. 67 | } 68 | } 69 | 70 | \bold{Calculations are performed in integer arithmetic} 71 | after subtracting \code{x0,y0} from the coordinates, 72 | dividing by \code{eps}, and rounding to the nearest integer. 73 | Thus, \code{eps} is the effective spatial resolution. 74 | The default values ensure reasonable accuracy. 75 | } 76 | \value{ 77 | Data specifying polygons, in the same format as \code{A}. 78 | } 79 | \author{Angus Johnson. 80 | Ported to \R by Adrian Baddeley 81 | \email{Adrian.Baddeley@curtin.edu.au}. 82 | } 83 | \references{ 84 | Clipper Website: \url{http://www.angusj.com} 85 | } 86 | \seealso{ 87 | \code{\link{polyclip}}, 88 | \code{\link{polyoffset}}, 89 | \code{\link{polylineoffset}}, 90 | \code{\link{polyminkowski}} 91 | } 92 | \examples{ 93 | theta <- 2 * pi * (0:5) * 2/5 94 | 95 | A <- list(list(x=sin(theta), y=cos(theta))) 96 | B <- polysimplify(A, filltype="nonzero") 97 | 98 | opa <- par(mfrow=c(1,2)) 99 | plot(c(-1,1),c(-1,1), type="n", axes=FALSE, xlab="", ylab="") 100 | with(A[[1]], segments(x[-6], y[-6], x[-1], y[-1], col="red")) 101 | points(A[[1]], col="red") 102 | 103 | with(A[[1]], text(x[1:5], y[1:5], labels=1:5, cex=2)) 104 | plot(c(-1,1),c(-1,1), type="n", axes=FALSE, xlab="", ylab="") 105 | polygon(B[[1]], lwd=3, col="green") 106 | with(B[[1]], text(x,y,labels=seq_along(x), cex=2)) 107 | par(opa) 108 | } 109 | \keyword{spatial} 110 | \keyword{manip} 111 | 112 | -------------------------------------------------------------------------------- /man/polyoffset.Rd: -------------------------------------------------------------------------------- 1 | \name{polyoffset} 2 | \alias{polyoffset} 3 | \title{Polygon Offset} 4 | \description{ 5 | Given a polygonal region, compute the offset region (aka: guard region, 6 | buffer region, morphological dilation) formed by shifting the 7 | boundary outwards by a specified distance. 8 | } 9 | \usage{ 10 | polyoffset(A, delta, 11 | \dots, 12 | eps, x0, y0, 13 | miterlim=2, arctol=abs(delta)/100, 14 | jointype=c("square", "round", "miter")) 15 | } 16 | \arguments{ 17 | \item{A}{Data specifying polygons. See Details.} 18 | \item{delta}{Distance over which the boundary should be shifted.} 19 | \item{\dots}{Ignored.} 20 | \item{eps}{Spatial resolution for coordinates.} 21 | \item{x0,y0}{Spatial origin for coordinates.} 22 | \item{miterlim,arctol}{Tolerance parameters: see Details.} 23 | \item{jointype}{ 24 | Type of join operation to be performed at each vertex. 25 | See Details. 26 | } 27 | } 28 | \value{ 29 | Data specifying polygons, in the same format as \code{A}. 30 | } 31 | \details{ 32 | This is part of an interface to the polygon-clipping library 33 | \code{Clipper} written by Angus Johnson. 34 | 35 | Given a polygonal region \code{A}, 36 | the function \code{polyoffset} computes the offset region 37 | (also known as the morphological dilation, guard region, 38 | buffer region, etc) obtained by shifting the boundary of \code{A} 39 | outward by the distance \code{delta}. 40 | 41 | The argument \code{A} represents a region in the 42 | Euclidean plane bounded by closed polygons. The format is either 43 | \itemize{ 44 | \item 45 | a list containing two components \code{x} and \code{y} 46 | giving the coordinates of the vertices of a single polygon. 47 | The last vertex should 48 | not repeat the first vertex. 49 | \item 50 | a \code{list} of \code{list(x,y)} structures giving 51 | the coordinates of the vertices of several polygons. 52 | } 53 | Note that calculations are performed in integer arithmetic: see below. 54 | 55 | The argument \code{jointype} determines what happens at the convex vertices 56 | of \code{A}. See the Examples for illustrations. 57 | \itemize{ 58 | \item \code{jointype="round"}: a circular arc is generated. 59 | \item \code{jointype="square"}: the circular arc is 60 | replaced by a single straight line. 61 | \item \code{jointype="miter"}: the circular arc is 62 | omitted entirely, or replaced by a single straight line. 63 | } 64 | 65 | The arguments \code{miterlim} and \code{arctol} are tolerances. 66 | \itemize{ 67 | \item if \code{jointype="round"}, then \code{arctol} is the maximum 68 | permissible distance between the true circular arc and its 69 | discretised approximation. 70 | \item if \code{jointype="miter"}, then \code{miterlimit * delta} 71 | is the maximum permissible displacement between the original vertex and the 72 | corresponding offset vertex if the circular arc were to be 73 | omitted entirely. The default is \code{miterlimit=2} 74 | which is also the minimum value. 75 | } 76 | 77 | \bold{Calculations are performed in integer arithmetic} 78 | after subtracting \code{x0,y0} from the coordinates, 79 | dividing by \code{eps}, and rounding to the nearest 64-bit integer. 80 | Thus, \code{eps} is the effective spatial resolution. 81 | The default values ensure reasonable accuracy. 82 | } 83 | \author{Angus Johnson. 84 | Ported to \R by Adrian Baddeley 85 | \email{Adrian.Baddeley@curtin.edu.au}. 86 | } 87 | \seealso{ 88 | \code{\link{polylineoffset}}, 89 | \code{\link{polyclip}}, 90 | \code{\link{polysimplify}}, 91 | \code{\link{polyminkowski}} 92 | } 93 | \examples{ 94 | A <- list(list(x=c(4,8,8,2,6), y=c(3,3,8,8,6))) 95 | plot(c(0,10),c(0,10), type="n", main="jointype=square", axes=FALSE, xlab="", ylab="") 96 | polygon(A[[1]], col="grey") 97 | C <- polyoffset(A, 1, jointype="square") 98 | polygon(C[[1]], lwd=3, border="blue") 99 | plot(c(0,10),c(0,10), type="n", main="jointype=round", axes=FALSE, xlab="", ylab="") 100 | polygon(A[[1]], col="grey") 101 | C <- polyoffset(A, 1, jointype="round") 102 | polygon(C[[1]], lwd=3, border="blue") 103 | plot(c(0,10),c(0,10), type="n", main="jointype=miter", axes=FALSE, xlab="", ylab="") 104 | polygon(A[[1]], col="grey") 105 | C <- polyoffset(A, 1, jointype="miter") 106 | polygon(C[[1]], lwd=3, border="blue") 107 | } 108 | \references{ 109 | Clipper Website: \url{http://www.angusj.com} 110 | 111 | Vatti, B. (1992) A generic solution to polygon clipping. 112 | \emph{Communications of the ACM} \bold{35} (7) 56--63. 113 | \url{http://portal.acm.org/citation.cfm?id=129906} 114 | 115 | Agoston, M.K. (2005) 116 | \emph{Computer graphics and geometric modeling: 117 | implementation and algorithms.} 118 | Springer-Verlag. 119 | \url{http://books.google.com/books?q=vatti+clipping+agoston} 120 | 121 | Chen, X. and McMains, S. (2005) 122 | Polygon Offsetting by Computing Winding Numbers. 123 | Paper no. DETC2005-85513 in \emph{Proceedings of IDETC/CIE 2005} 124 | (ASME 2005 International Design Engineering Technical Conferences 125 | and Computers and Information in Engineering Conference), 126 | pp. 565--575 127 | \url{http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf} 128 | } 129 | \keyword{spatial} 130 | \keyword{math} 131 | -------------------------------------------------------------------------------- /man/polyclip.Rd: -------------------------------------------------------------------------------- 1 | \name{polyclip} 2 | \alias{polyclip} 3 | \title{Polygon Clipping} 4 | \description{ 5 | Find intersection, union or set difference of two polygonal regions. 6 | } 7 | \usage{ 8 | polyclip(A, B, op=c("intersection", "union", "minus", "xor"), 9 | \dots, 10 | eps, x0, y0, 11 | fillA=c("evenodd", "nonzero", "positive", "negative"), 12 | fillB=c("evenodd", "nonzero", "positive", "negative")) 13 | } 14 | \arguments{ 15 | \item{A,B}{ 16 | Data specifying polygons. See Details. 17 | } 18 | \item{op}{Set operation to be performed to combine \code{A} and \code{B}.} 19 | \item{\dots}{Ignored.} 20 | \item{eps}{Spatial resolution for coordinates.} 21 | \item{x0,y0}{Spatial origin for coordinates.} 22 | \item{fillA,fillB}{Polygon-filling rule for \code{A} and \code{B}.} 23 | } 24 | \value{ 25 | Data specifying polygons, in the same format as \code{A} and \code{B}. 26 | } 27 | \details{ 28 | This is an interface to the polygon-clipping library 29 | \code{Clipper} written by Angus Johnson. 30 | 31 | Given two polygonal regions \code{A} and \code{B} 32 | the function \code{polyclip} performs one of the following 33 | geometrical operations: 34 | \itemize{ 35 | \item \code{op="intersection"}: set intersection of \code{A} and \code{B}. 36 | \item \code{op="union"}: set union of \code{A} and \code{B}. 37 | \item \code{op="minus"}: set subtraction (sometimes called set difference): 38 | the region covered by \code{A} that is not covered by \code{B}. 39 | \item \code{op="xor"}: exclusive set difference (sometimes called 40 | exclusive-or): the region covered by exactly one of the sets 41 | \code{A} and \code{B}. 42 | } 43 | 44 | Each of the arguments \code{A} and \code{B} represents a region in the 45 | Euclidean plane bounded by closed polygons. The format of these 46 | arguments is either 47 | \itemize{ 48 | \item 49 | a list containing two components \code{x} and \code{y} 50 | giving the coordinates of the vertices of a single polygon. 51 | The last vertex should 52 | not repeat the first vertex. 53 | \item 54 | a \code{list} of \code{list(x,y)} structures giving 55 | the coordinates of the vertices of several polygons. 56 | } 57 | Note that calculations are performed in integer arithmetic: see below. 58 | 59 | The interpretation of the polygons 60 | depends on the \emph{polygon-filling rule} for \code{A} and \code{B} 61 | that is specified by the arguments \code{fillA} and \code{fillB} 62 | respectively. 63 | \describe{ 64 | \item{Even-Odd:}{ 65 | The default rule is \emph{even-odd} filling, 66 | in which every polygon edge demarcates a boundary between 67 | the inside and outside of the region. 68 | It does not matter whether a polygon is traversed in 69 | clockwise or anticlockwise order. Holes are determined 70 | simply by their locations relative to other polygons such that 71 | outers contain holes and holes contain outers. 72 | } 73 | \item{Non-Zero:}{ 74 | Under the \emph{nonzero} filling rule, an outer boundary must be 75 | traversed in clockwise order, while a hole must be traversed 76 | in anticlockwise order. 77 | } 78 | \item{Positive:}{ 79 | Under the \code{positive} filling rule, the filled region 80 | consists of all points with positive winding number. 81 | } 82 | \item{Negative:}{ 83 | Under the \code{negative} filling rule, the filled region 84 | consists of all points with negative winding number. 85 | } 86 | } 87 | 88 | \bold{Calculations are performed in integer arithmetic} 89 | after subtracting \code{x0,y0} from the coordinates, 90 | dividing by \code{eps}, and rounding to the nearest integer. 91 | Thus, \code{eps} is the effective spatial resolution. 92 | The default values ensure reasonable accuracy. 93 | } 94 | \seealso{ 95 | \code{\link{polysimplify}}, 96 | \code{\link{polyoffset}}, 97 | \code{\link{polylineoffset}}, 98 | \code{\link{polyminkowski}} 99 | } 100 | \author{Angus Johnson. 101 | Ported to \R by Adrian Baddeley 102 | \email{Adrian.Baddeley@curtin.edu.au}. 103 | } 104 | \examples{ 105 | A <- list(list(x=1:10, y=c(1:5,5:1))) 106 | B <- list(list(x=c(2,8,8,2),y=c(0,0,10,10))) 107 | plot(c(0,10),c(0,10), type="n", axes=FALSE, xlab="", ylab="") 108 | polygon(A[[1]]) 109 | polygon(B[[1]]) 110 | C <- polyclip(A, B) 111 | polygon(C[[1]], lwd=3, col=3) 112 | } 113 | \references{ 114 | Clipper Website: \url{http://www.angusj.com} 115 | 116 | Vatti, B. (1992) A generic solution to polygon clipping. 117 | \emph{Communications of the ACM} \bold{35} (7) 56--63. 118 | \url{http://portal.acm.org/citation.cfm?id=129906} 119 | 120 | Agoston, M.K. (2005) 121 | \emph{Computer graphics and geometric modeling: 122 | implementation and algorithms.} 123 | Springer-Verlag. 124 | \url{http://books.google.com/books?q=vatti+clipping+agoston} 125 | 126 | Chen, X. and McMains, S. (2005) 127 | Polygon Offsetting by Computing Winding Numbers. 128 | Paper no. DETC2005-85513 in \emph{Proceedings of IDETC/CIE 2005} 129 | (ASME 2005 International Design Engineering Technical Conferences 130 | and Computers and Information in Engineering Conference), 131 | pp. 565--575 132 | \url{http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf} 133 | } 134 | \keyword{spatial} 135 | \keyword{math} 136 | -------------------------------------------------------------------------------- /man/polylineoffset.Rd: -------------------------------------------------------------------------------- 1 | \name{polylineoffset} 2 | \alias{polylineoffset} 3 | \title{Polygonal Line Offset} 4 | \description{ 5 | Given a list of polygonal lines, compute the offset region (guard region, 6 | buffer region, morphological dilation) formed by shifting the 7 | boundary outwards by a specified distance. 8 | } 9 | \usage{ 10 | polylineoffset(A, delta, 11 | \dots, 12 | eps, x0, y0, 13 | miterlim=2, arctol=abs(delta)/100, 14 | jointype=c("square", "round", "miter"), 15 | endtype = c("closedpolygon", "closedline", 16 | "openbutt", "opensquare", "openround", 17 | "closed", "butt", "square", "round")) 18 | } 19 | \arguments{ 20 | \item{A}{Data specifying polygons. See Details.} 21 | \item{delta}{Distance over which the boundary should be shifted.} 22 | \item{\dots}{Ignored.} 23 | \item{eps}{Spatial resolution for coordinates.} 24 | \item{x0,y0}{Spatial origin for coordinates.} 25 | \item{miterlim,arctol}{Tolerance parameters: see Details.} 26 | \item{jointype}{ 27 | Type of join operation to be performed at each vertex. 28 | See Details. 29 | } 30 | \item{endtype}{ 31 | Type of geometrical operation to be performed at the start and end 32 | of each line. See Details. 33 | } 34 | } 35 | \value{ 36 | Data specifying polygons, in the same format as \code{A}. 37 | } 38 | \details{ 39 | This is part of an interface to the polygon-clipping library 40 | \code{Clipper} written by Angus Johnson. 41 | 42 | Given a list of polygonal lines \code{A}, 43 | the function \code{polylineoffset} computes the offset region 44 | (also known as the morphological dilation, guard region, 45 | buffer region, etc) obtained by shifting the boundary of \code{A} 46 | outward by the distance \code{delta}. 47 | 48 | The argument \code{A} represents a polygonal line (broken line) 49 | or a list of broken lines. The format is either 50 | \itemize{ 51 | \item 52 | a list containing two components \code{x} and \code{y} 53 | giving the coordinates of successive vertices of the broken line. 54 | \item 55 | a \code{list} of \code{list(x,y)} structures giving 56 | the coordinates of the vertices of several broken lines. 57 | } 58 | Lines may be self-intersecting and different lines may intersect each other. 59 | Note that calculations are performed in integer arithmetic: see below. 60 | 61 | The argument \code{jointype} determines what happens at the vertices 62 | of each line. See the Examples for illustrations. 63 | \itemize{ 64 | \item \code{jointype="round"}: a circular arc is generated. 65 | \item \code{jointype="square"}: the circular arc is 66 | replaced by a single straight line. 67 | \item \code{jointype="miter"}: the circular arc is 68 | omitted entirely, or replaced by a single straight line. 69 | } 70 | The argument \code{endtype} determines what happens at the beginning 71 | and end of each line. See the Examples for illustrations. 72 | \itemize{ 73 | \item \code{endtype="closedpolygon"}: ends are joined together (using the 74 | \code{jointype} value) and the path filled as a polygon. 75 | \item \code{endtype="closedline"}: ends are joined together (using the 76 | \code{jointype} value) and the path is filled as a polyline. 77 | \item \code{endtype="openbutt"}: ends are squared off abruptly. 78 | \item \code{endtype="opensquare"}: 79 | ends are squared off at distance \code{delta}. 80 | \item \code{endtype="openround"}: ends are replaced by a semicircular arc. 81 | } 82 | The values \code{endtype="closed"}, \code{"butt"}, \code{"square"} 83 | and \code{"round"} are deprecated; they are 84 | equivalent to \code{endtype="closedpolygon"}, 85 | \code{"openbutt"}, \code{"opensquare"} and \code{"openround"} 86 | respectively. 87 | 88 | The arguments \code{miterlim} and \code{arctol} are tolerances. 89 | \itemize{ 90 | \item if \code{jointype="round"}, then \code{arctol} is the maximum 91 | permissible distance between the true circular arc and its 92 | discretised approximation. 93 | \item if \code{jointype="miter"}, then \code{miterlimit * delta} 94 | is the maximum permissible displacement between the original vertex and the 95 | corresponding offset vertex if the circular arc were to be 96 | omitted entirely. The default is \code{miterlimit=2} 97 | which is also the minimum value. 98 | } 99 | 100 | 101 | \bold{Calculations are performed in integer arithmetic} 102 | after subtracting \code{x0,y0} from the coordinates, 103 | dividing by \code{eps}, and rounding to the nearest integer. 104 | Thus, \code{eps} is the effective spatial resolution. 105 | The default values ensure reasonable accuracy. 106 | } 107 | \author{Angus Johnson. 108 | Ported to \R by Adrian Baddeley 109 | \email{Adrian.Baddeley@curtin.edu.au}. 110 | } 111 | \seealso{ 112 | \code{\link{polyoffset}}, 113 | \code{\link{polysimplify}}, 114 | \code{\link{polyclip}}, 115 | \code{\link{polyminkowski}} 116 | } 117 | \examples{ 118 | A <- list(list(x=c(4,8,8,2,6), y=c(3,3,8,8,6))) 119 | 120 | plot(c(0,10),c(0,10), type="n", 121 | main="jointype=square, endtype=opensquare", 122 | axes=FALSE, xlab="", ylab="") 123 | lines(A[[1]], col="grey", lwd=3) 124 | C <- polylineoffset(A, 0.5, jointype="square", endtype="opensquare") 125 | polygon(C[[1]], lwd=3, border="blue") 126 | 127 | plot(c(0,10),c(0,10), type="n", 128 | main="jointype=round, endtype=openround", 129 | axes=FALSE, xlab="", ylab="") 130 | lines(A[[1]], col="grey", lwd=3) 131 | C <- polylineoffset(A, 0.5, jointype="round", endtype="openround") 132 | polygon(C[[1]], lwd=3, border="blue") 133 | } 134 | \references{ 135 | Clipper Website: \url{http://www.angusj.com} 136 | 137 | Vatti, B. (1992) A generic solution to polygon clipping. 138 | \emph{Communications of the ACM} \bold{35} (7) 56--63. 139 | \url{http://portal.acm.org/citation.cfm?id=129906} 140 | 141 | Agoston, M.K. (2005) 142 | \emph{Computer graphics and geometric modeling: 143 | implementation and algorithms.} 144 | Springer-Verlag. 145 | \url{http://books.google.com/books?q=vatti+clipping+agoston} 146 | 147 | Chen, X. and McMains, S. (2005) 148 | Polygon Offsetting by Computing Winding Numbers. 149 | Paper no. DETC2005-85513 in \emph{Proceedings of IDETC/CIE 2005} 150 | (ASME 2005 International Design Engineering Technical Conferences 151 | and Computers and Information in Engineering Conference), 152 | pp. 565--575 153 | \url{http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf} 154 | } 155 | \keyword{spatial} 156 | \keyword{math} 157 | -------------------------------------------------------------------------------- /R/clipper.R: -------------------------------------------------------------------------------- 1 | # 2 | # clipper.R 3 | # 4 | # Interface to Clipper C++ code 5 | # 6 | # $Revision: 1.13 $ $Date: 2016/03/24 00:52:57 $ 7 | # 8 | 9 | validxy <- function(P) { 10 | is.list(P) && all(c("x","y") %in% names(P)) && 11 | is.vector(P$x) && is.vector(P$y) && length(P$x)==length(P$y) 12 | } 13 | 14 | validpoly <- function(P) { 15 | is.list(P) && all(unlist(lapply(P, validxy))) 16 | } 17 | 18 | xrange <- function(z) { range(z$x) } 19 | yrange <- function(z) { range(z$y) } 20 | 21 | ensurexydouble <- function(P) lapply(P[c("x", "y")], 22 | "storage.mode<-", value="double") 23 | 24 | ensuredouble <- function(A) lapply(A, ensurexydouble) 25 | 26 | aspolygonlist <- function(A) lapply(A, "names<-", value=c("x", "y")) 27 | 28 | polysimplify <- 29 | function(A, 30 | ..., 31 | eps, x0, y0, 32 | filltype=c("evenodd", "nonzero", "positive", "negative") 33 | ) { 34 | # validate parameters and convert to integer codes 35 | filltype <- match.arg(filltype) 36 | pft <- match(filltype, c("evenodd", "nonzero", "positive", "negative")) 37 | # validate polygon 38 | if(!validpoly(A)) { 39 | if(validxy(A)) A <- list(A) else 40 | stop("Argument A should be a list of lists, each containing vectors x,y") 41 | } 42 | # determine value of 'eps' if missing 43 | if(missing(eps) || missing(x0) || missing(y0)) { 44 | xr <- range(range(unlist(lapply(A, xrange)))) 45 | yr <- range(range(unlist(lapply(A, yrange)))) 46 | if(missing(eps)) eps <- max(diff(xr), diff(yr))/1e9 47 | if(missing(x0)) x0 <- mean(xr) 48 | if(missing(y0)) y0 <- mean(yr) 49 | } 50 | # call clipper library on each component path 51 | result <- list() 52 | A <- ensuredouble(A) 53 | storage.mode(pft) <- "integer" 54 | storage.mode(x0) <- storage.mode(y0) <- storage.mode(eps) <- "double" 55 | result <- .Call("Csimplify", 56 | A, pft, x0, y0, eps, 57 | PACKAGE = "polyclip") 58 | return(aspolygonlist(result)) 59 | } 60 | 61 | polyclip <- 62 | function(A, B, 63 | op=c("intersection", "union", "minus", "xor"), 64 | ..., 65 | eps, x0, y0, 66 | fillA=c("evenodd", "nonzero", "positive", "negative"), 67 | fillB=c("evenodd", "nonzero", "positive", "negative") 68 | ) { 69 | # validate parameters and convert to integer codes 70 | op <- match.arg(op) 71 | fillA <- match.arg(fillA) 72 | fillB <- match.arg(fillB) 73 | ct <- match(op, c("intersection", "union", "minus", "xor")) 74 | pftA <- match(fillA, c("evenodd", "nonzero", "positive", "negative")) 75 | pftB <- match(fillB, c("evenodd", "nonzero", "positive", "negative")) 76 | # validate polygons and rescale 77 | if(!validpoly(A)) { 78 | if(validxy(A)) A <- list(A) else 79 | stop("Argument A should be a list of lists, each containing vectors x,y") 80 | } 81 | if(!validpoly(B)) { 82 | if(validxy(B)) B <- list(B) else 83 | stop("Argument B should be a list of lists, each containing vectors x,y") 84 | } 85 | # determine value of 'eps' if missing 86 | if(missing(eps) || missing(x0) || missing(y0)) { 87 | xr <- range(range(unlist(lapply(A, xrange))), 88 | range(unlist(lapply(B, xrange)))) 89 | yr <- range(range(unlist(lapply(A, yrange))), 90 | range(unlist(lapply(B, yrange)))) 91 | if(missing(eps)) eps <- max(diff(xr), diff(yr))/1e9 92 | if(missing(x0)) x0 <- mean(xr) 93 | if(missing(y0)) y0 <- mean(yr) 94 | } 95 | # call clipper library 96 | A <- ensuredouble(A) 97 | B <- ensuredouble(B) 98 | storage.mode(ct) <- storage.mode(pftA) <- storage.mode(pftB) <- "integer" 99 | storage.mode(x0) <- storage.mode(y0) <- storage.mode(eps) <- "double" 100 | ans <- .Call("Cclipbool", 101 | A, B, pftA, pftB, ct, 102 | x0, y0, eps, 103 | PACKAGE = "polyclip") 104 | return(aspolygonlist(ans)) 105 | } 106 | 107 | polyoffset <- 108 | function(A, delta, 109 | ..., 110 | eps, x0, y0, 111 | miterlim=2, arctol=abs(delta)/100, 112 | jointype = c("square", "round", "miter") 113 | ) { 114 | # validate parameters and convert to integer codes 115 | jointype <- match.arg(jointype) 116 | jt <- match(jointype, c("square", "round", "miter")) 117 | # validate polygons and rescale 118 | if(!validpoly(A)) { 119 | if(validxy(A)) A <- list(A) else 120 | stop("Argument A should be a list of lists, each containing vectors x,y") 121 | } 122 | # determine value of 'eps' if missing 123 | if(missing(eps) || missing(x0) || missing(y0)) { 124 | xr <- range(unlist(lapply(A, xrange))) 125 | yr <- range(unlist(lapply(A, yrange))) 126 | if(missing(eps)) eps <- max(diff(xr), diff(yr))/1e9 127 | if(missing(x0)) x0 <- mean(xr) 128 | if(missing(y0)) y0 <- mean(yr) 129 | } 130 | # arc tolerance 131 | arctol <- max(eps/4, arctol) 132 | # call clipper library 133 | A <- ensuredouble(A) 134 | storage.mode(jt) <- "integer" 135 | storage.mode(delta) <- 136 | storage.mode(miterlim) <- storage.mode(arctol) <- "double" 137 | storage.mode(x0) <- storage.mode(y0) <- storage.mode(eps) <- "double" 138 | ans <- .Call("Cpolyoffset", A, delta, jt, 139 | miterlim, arctol, x0, y0, eps, 140 | PACKAGE = "polyclip") 141 | return(aspolygonlist(ans)) 142 | } 143 | 144 | 145 | polylineoffset <- 146 | function(A, delta, 147 | ..., 148 | eps, x0, y0, 149 | miterlim=2, arctol=abs(delta)/100, 150 | jointype = c("square", "round", "miter"), 151 | endtype = c("closedpolygon", "closedline", 152 | "openbutt", "opensquare", "openround", 153 | "closed", "butt", "square", "round") 154 | ) { 155 | ## validate parameters and convert to integer codes 156 | jointype <- match.arg(jointype) 157 | jt <- match(jointype, c("square", "round", "miter")) 158 | 159 | endtype <- match.arg(endtype) 160 | if(endtype == "closed") endtype <- "closedpolygon" 161 | if(endtype %in% c("butt", "square", "round")) 162 | endtype <- paste0("open", endtype) 163 | et <- match(endtype, c("closedpolygon", "closedline", 164 | "openbutt", "opensquare", "openround")) 165 | 166 | ## validate polygons and rescale 167 | if(!validpoly(A)) { 168 | if(validxy(A)) A <- list(A) else 169 | stop("Argument A should be a list of lists, each containing vectors x,y") 170 | } 171 | ## determine value of 'eps' if missing 172 | if(missing(eps) || missing(x0) || missing(y0)) { 173 | xr <- range(unlist(lapply(A, xrange))) 174 | yr <- range(unlist(lapply(A, yrange))) 175 | if(missing(eps)) eps <- max(diff(xr), diff(yr))/1e9 176 | if(missing(x0)) x0 <- mean(xr) 177 | if(missing(y0)) y0 <- mean(yr) 178 | } 179 | # arc tolerance 180 | arctol <- max(eps/4, arctol) 181 | # call clipper library 182 | A <- ensuredouble(A) 183 | storage.mode(jt) <- storage.mode(et) <- "integer" 184 | storage.mode(delta) <- storage.mode(miterlim) <- 185 | storage.mode(arctol) <- "double" 186 | storage.mode(x0) <- storage.mode(y0) <- storage.mode(eps) <- "double" 187 | ans <- .Call("Clineoffset", A, delta, jt, et, 188 | miterlim, arctol, x0, y0, eps, 189 | PACKAGE = "polyclip") 190 | return(aspolygonlist(ans)) 191 | } 192 | 193 | polyminkowski <- 194 | function(A, B, 195 | ..., 196 | eps, x0, y0, 197 | closed=TRUE 198 | ) { 199 | # validate parameters and convert to integer codes 200 | closed <- as.logical(closed) 201 | # validate polygons/paths 202 | if(!validpoly(A)) { 203 | if(validxy(A)) A <- list(A) else 204 | stop("Argument A should be a list of lists, each containing vectors x,y") 205 | } 206 | if(length(A) > 1) 207 | stop("Not implemented when A consists of more than one polygon") 208 | if(!validpoly(B)) { 209 | if(validxy(B)) B <- list(B) else 210 | stop("Argument B should be a list of lists, each containing vectors x,y") 211 | } 212 | # determine value of 'eps' if missing 213 | if(missing(eps) || missing(x0) || missing(y0)) { 214 | xr <- range(range(unlist(lapply(A, xrange)))) 215 | yr <- range(range(unlist(lapply(A, yrange)))) 216 | xr <- range(xr, range(unlist(lapply(B, xrange)))) 217 | yr <- range(yr, range(unlist(lapply(B, yrange)))) 218 | if(missing(eps)) eps <- max(diff(xr), diff(yr))/1e9 219 | if(missing(x0)) x0 <- xr[1] 220 | if(missing(y0)) y0 <- yr[1] - diff(yr)/16 221 | } 222 | # call clipper library on each component path 223 | A <- ensuredouble(A) 224 | B <- ensuredouble(B) 225 | storage.mode(x0) <- storage.mode(y0) <- storage.mode(eps) <- "double" 226 | storage.mode(closed) <- "logical" 227 | result <- .Call("Cminksum", 228 | A, B, closed, x0, y0, eps, 229 | PACKAGE = "polyclip") 230 | return(aspolygonlist(result)) 231 | } 232 | -------------------------------------------------------------------------------- /config.log: -------------------------------------------------------------------------------- 1 | This file contains any messages produced by compilers while 2 | running configure, to aid debugging if configure makes a mistake. 3 | 4 | It was created by polyclip configure 1.1-0, which was 5 | generated by GNU Autoconf 2.69. Invocation command line was 6 | 7 | $ ./configure 8 | 9 | ## --------- ## 10 | ## Platform. ## 11 | ## --------- ## 12 | 13 | hostname = red 14 | uname -m = i686 15 | uname -r = 3.2.0-55-generic 16 | uname -s = Linux 17 | uname -v = #85-Ubuntu SMP Wed Oct 2 13:43:27 UTC 2013 18 | 19 | /usr/bin/uname -p = unknown 20 | /bin/uname -X = unknown 21 | 22 | /bin/arch = unknown 23 | /usr/bin/arch -k = unknown 24 | /usr/convex/getsysinfo = unknown 25 | /usr/bin/hostinfo = unknown 26 | /bin/machine = unknown 27 | /usr/bin/oslevel = unknown 28 | /bin/universe = unknown 29 | 30 | PATH: /home/adrian/bin 31 | PATH: /usr/lib/lightdm/lightdm 32 | PATH: /usr/local/sbin 33 | PATH: /usr/local/bin 34 | PATH: /usr/sbin 35 | PATH: /usr/bin 36 | PATH: /sbin 37 | PATH: /bin 38 | PATH: /usr/games 39 | 40 | 41 | ## ----------- ## 42 | ## Core tests. ## 43 | ## ----------- ## 44 | 45 | configure:2003: checking for g++ 46 | configure:2019: found /usr/bin/g++ 47 | configure:2030: result: g++ 48 | configure:2057: checking for C++ compiler version 49 | configure:2066: g++ --version >&5 50 | g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 51 | Copyright (C) 2011 Free Software Foundation, Inc. 52 | This is free software; see the source for copying conditions. There is NO 53 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 54 | 55 | configure:2077: $? = 0 56 | configure:2066: g++ -v >&5 57 | Using built-in specs. 58 | COLLECT_GCC=g++ 59 | COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.6/lto-wrapper 60 | Target: i686-linux-gnu 61 | Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu 62 | Thread model: posix 63 | gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) 64 | configure:2077: $? = 0 65 | configure:2066: g++ -V >&5 66 | g++: error: unrecognized option '-V' 67 | g++: fatal error: no input files 68 | compilation terminated. 69 | configure:2077: $? = 4 70 | configure:2066: g++ -qversion >&5 71 | g++: error: unrecognized option '-qversion' 72 | g++: fatal error: no input files 73 | compilation terminated. 74 | configure:2077: $? = 4 75 | configure:2097: checking whether the C++ compiler works 76 | configure:2119: g++ conftest.cpp >&5 77 | configure:2123: $? = 0 78 | configure:2171: result: yes 79 | configure:2174: checking for C++ compiler default output file name 80 | configure:2176: result: a.out 81 | configure:2182: checking for suffix of executables 82 | configure:2189: g++ -o conftest conftest.cpp >&5 83 | configure:2193: $? = 0 84 | configure:2215: result: 85 | configure:2237: checking whether we are cross compiling 86 | configure:2245: g++ -o conftest conftest.cpp >&5 87 | configure:2249: $? = 0 88 | configure:2256: ./conftest 89 | configure:2260: $? = 0 90 | configure:2275: result: no 91 | configure:2280: checking for suffix of object files 92 | configure:2302: g++ -c conftest.cpp >&5 93 | configure:2306: $? = 0 94 | configure:2327: result: o 95 | configure:2331: checking whether we are using the GNU C++ compiler 96 | configure:2350: g++ -c conftest.cpp >&5 97 | configure:2350: $? = 0 98 | configure:2359: result: yes 99 | configure:2368: checking whether g++ accepts -g 100 | configure:2388: g++ -c -g conftest.cpp >&5 101 | configure:2388: $? = 0 102 | configure:2429: result: yes 103 | configure:2453: checking for int64_t 104 | configure:2453: g++ -c conftest.cpp >&5 105 | configure:2453: $? = 0 106 | configure:2453: g++ -c conftest.cpp >&5 107 | conftest.cpp: In function 'int main()': 108 | conftest.cpp:14:21: error: expected primary-expression before ')' token 109 | configure:2453: $? = 1 110 | configure: failed program was: 111 | | /* confdefs.h */ 112 | | #define PACKAGE_NAME "polyclip" 113 | | #define PACKAGE_TARNAME "polyclip" 114 | | #define PACKAGE_VERSION "1.1-0" 115 | | #define PACKAGE_STRING "polyclip 1.1-0" 116 | | #define PACKAGE_BUGREPORT "" 117 | | #define PACKAGE_URL "" 118 | | /* end confdefs.h. */ 119 | | #include 120 | | 121 | | int 122 | | main () 123 | | { 124 | | if (sizeof ((int64_t))) 125 | | return 0; 126 | | ; 127 | | return 0; 128 | | } 129 | configure:2453: result: yes 130 | configure:2911: checking for uint64_t 131 | configure:2911: g++ -c conftest.cpp >&5 132 | configure:2911: $? = 0 133 | configure:2911: g++ -c conftest.cpp >&5 134 | conftest.cpp: In function 'int main()': 135 | conftest.cpp:15:22: error: expected primary-expression before ')' token 136 | configure:2911: $? = 1 137 | configure: failed program was: 138 | | /* confdefs.h */ 139 | | #define PACKAGE_NAME "polyclip" 140 | | #define PACKAGE_TARNAME "polyclip" 141 | | #define PACKAGE_VERSION "1.1-0" 142 | | #define PACKAGE_STRING "polyclip 1.1-0" 143 | | #define PACKAGE_BUGREPORT "" 144 | | #define PACKAGE_URL "" 145 | | #define HAVE_INT64_T 1 146 | | /* end confdefs.h. */ 147 | | #include 148 | | 149 | | int 150 | | main () 151 | | { 152 | | if (sizeof ((uint64_t))) 153 | | return 0; 154 | | ; 155 | | return 0; 156 | | } 157 | configure:2911: result: yes 158 | configure:3128: creating ./config.status 159 | 160 | ## ---------------------- ## 161 | ## Running config.status. ## 162 | ## ---------------------- ## 163 | 164 | This file was extended by polyclip config.status 1.1-0, which was 165 | generated by GNU Autoconf 2.69. Invocation command line was 166 | 167 | CONFIG_FILES = 168 | CONFIG_HEADERS = 169 | CONFIG_LINKS = 170 | CONFIG_COMMANDS = 171 | $ ./config.status 172 | 173 | on red 174 | 175 | config.status:723: creating src/Makevars 176 | 177 | ## ---------------- ## 178 | ## Cache variables. ## 179 | ## ---------------- ## 180 | 181 | ac_cv_cxx_compiler_gnu=yes 182 | ac_cv_env_CCC_set= 183 | ac_cv_env_CCC_value= 184 | ac_cv_env_CPPFLAGS_set= 185 | ac_cv_env_CPPFLAGS_value= 186 | ac_cv_env_CXXCPP_set= 187 | ac_cv_env_CXXCPP_value= 188 | ac_cv_env_CXXFLAGS_set= 189 | ac_cv_env_CXXFLAGS_value= 190 | ac_cv_env_CXX_set= 191 | ac_cv_env_CXX_value= 192 | ac_cv_env_LDFLAGS_set= 193 | ac_cv_env_LDFLAGS_value= 194 | ac_cv_env_LIBS_set= 195 | ac_cv_env_LIBS_value= 196 | ac_cv_env_build_alias_set= 197 | ac_cv_env_build_alias_value= 198 | ac_cv_env_host_alias_set= 199 | ac_cv_env_host_alias_value= 200 | ac_cv_env_target_alias_set= 201 | ac_cv_env_target_alias_value= 202 | ac_cv_objext=o 203 | ac_cv_prog_ac_ct_CXX=g++ 204 | ac_cv_prog_cxx_g=yes 205 | ac_cv_type_int64_t=yes 206 | ac_cv_type_uint64_t=yes 207 | 208 | ## ----------------- ## 209 | ## Output variables. ## 210 | ## ----------------- ## 211 | 212 | CPPFLAGS='' 213 | CXX='g++' 214 | CXXCPP='' 215 | CXXFLAGS='' 216 | DEFS='-DPACKAGE_NAME=\"polyclip\" -DPACKAGE_TARNAME=\"polyclip\" -DPACKAGE_VERSION=\"1.1-0\" -DPACKAGE_STRING=\"polyclip\ 1.1-0\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DHAVE_INT64_T=1 -DHAVE_UINT64_T=1' 217 | ECHO_C='' 218 | ECHO_N='-n' 219 | ECHO_T='' 220 | EGREP='' 221 | EXEEXT='' 222 | GREP='' 223 | LDFLAGS='' 224 | LIBOBJS='' 225 | LIBS='' 226 | LTLIBOBJS='' 227 | OBJEXT='o' 228 | PACKAGE_BUGREPORT='' 229 | PACKAGE_NAME='polyclip' 230 | PACKAGE_STRING='polyclip 1.1-0' 231 | PACKAGE_TARNAME='polyclip' 232 | PACKAGE_URL='' 233 | PACKAGE_VERSION='1.1-0' 234 | PATH_SEPARATOR=':' 235 | POLYCLIP_CPPFLAGS='-DPOLYCLIP_LONG64="int64_t" -DPOLYCLIP_ULONG64="uint64_t"' 236 | SHELL='/bin/bash' 237 | ac_ct_CXX='g++' 238 | bindir='${exec_prefix}/bin' 239 | build_alias='' 240 | datadir='${datarootdir}' 241 | datarootdir='${prefix}/share' 242 | docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' 243 | dvidir='${docdir}' 244 | exec_prefix='${prefix}' 245 | host_alias='' 246 | htmldir='${docdir}' 247 | includedir='${prefix}/include' 248 | infodir='${datarootdir}/info' 249 | libdir='${exec_prefix}/lib' 250 | libexecdir='${exec_prefix}/libexec' 251 | localedir='${datarootdir}/locale' 252 | localstatedir='${prefix}/var' 253 | mandir='${datarootdir}/man' 254 | oldincludedir='/usr/include' 255 | pdfdir='${docdir}' 256 | prefix='/usr/local' 257 | program_transform_name='s,x,x,' 258 | psdir='${docdir}' 259 | sbindir='${exec_prefix}/sbin' 260 | sharedstatedir='${prefix}/com' 261 | sysconfdir='${prefix}/etc' 262 | target_alias='' 263 | 264 | ## ----------- ## 265 | ## confdefs.h. ## 266 | ## ----------- ## 267 | 268 | /* confdefs.h */ 269 | #define PACKAGE_NAME "polyclip" 270 | #define PACKAGE_TARNAME "polyclip" 271 | #define PACKAGE_VERSION "1.1-0" 272 | #define PACKAGE_STRING "polyclip 1.1-0" 273 | #define PACKAGE_BUGREPORT "" 274 | #define PACKAGE_URL "" 275 | #define HAVE_INT64_T 1 276 | #define HAVE_UINT64_T 1 277 | 278 | configure: exit 0 279 | -------------------------------------------------------------------------------- /src/clipper.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * * 3 | * Author : Angus Johnson * 4 | * Version : 6.4.0 * 5 | * Date : 2 July 2015 * 6 | * Website : http://www.angusj.com * 7 | * Copyright : Angus Johnson 2010-2015 * 8 | * * 9 | * License: * 10 | * Use, modification & distribution is subject to Boost Software License Ver 1. * 11 | * http://www.boost.org/LICENSE_1_0.txt * 12 | * * 13 | * Attributions: * 14 | * The code in this library is an extension of Bala Vatti's clipping algorithm: * 15 | * "A generic solution to polygon clipping" * 16 | * Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * 17 | * http://portal.acm.org/citation.cfm?id=129906 * 18 | * * 19 | * Computer graphics and geometric modeling: implementation and algorithms * 20 | * By Max K. Agoston * 21 | * Springer; 1 edition (January 4, 2005) * 22 | * http://books.google.com/books?q=vatti+clipping+agoston * 23 | * * 24 | * See also: * 25 | * "Polygon Offsetting by Computing Winding Numbers" * 26 | * Paper no. DETC2005-85513 pp. 565-575 * 27 | * ASME 2005 International Design Engineering Technical Conferences * 28 | * and Computers and Information in Engineering Conference (IDETC/CIE2005) * 29 | * September 24-28, 2005 , Long Beach, California, USA * 30 | * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * 31 | * * 32 | *******************************************************************************/ 33 | 34 | /**************************************************************************** 35 | * * 36 | * Modified by Adrian Baddeley * 37 | * for inclusion in an 'R' package * 38 | * * 39 | * Alterations are switched on/off by variable 'R_PACKAGE' * 40 | * Alterations are marked by 'ajb' * 41 | ****************************************************************************/ 42 | 43 | // ajb start 44 | #define R_PACKAGE 45 | // ajb end 46 | 47 | #ifndef clipper_hpp 48 | #define clipper_hpp 49 | 50 | #define CLIPPER_VERSION "6.2.6" 51 | 52 | //use_int32: When enabled 32bit ints are used instead of 64bit ints. This 53 | //improve performance but coordinate values are limited to the range +/- 46340 54 | //#define use_int32 55 | 56 | //use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance. 57 | //#define use_xyz 58 | 59 | //use_lines: Enables line clipping. Adds a very minor cost to performance. 60 | #define use_lines 61 | 62 | //use_deprecated: Enables temporary support for the obsolete functions 63 | //#define use_deprecated 64 | 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | 75 | namespace ClipperLib { 76 | 77 | enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor }; 78 | enum PolyType { ptSubject, ptClip }; 79 | //By far the most widely used winding rules for polygon filling are 80 | //EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32) 81 | //Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL) 82 | //see http://glprogramming.com/red/chapter11.html 83 | enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; 84 | 85 | #ifdef use_int32 86 | typedef int cInt; 87 | static cInt const loRange = 0x7FFF; 88 | static cInt const hiRange = 0x7FFF; 89 | #else 90 | // ajb start 91 | #ifdef POLYCLIP_LONG64 92 | // 64-bit types in are found using a configuration script 93 | #include 94 | typedef POLYCLIP_LONG64 cInt; 95 | typedef POLYCLIP_LONG64 long64; 96 | typedef POLYCLIP_ULONG64 ulong64; 97 | #else 98 | // e.g. Windows 99 | typedef signed long long cInt; 100 | typedef signed long long long64; //used by Int128 class 101 | typedef unsigned long long ulong64; 102 | #endif 103 | static cInt const loRange = 0x3FFFFFFF; 104 | // was: static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL; 105 | static cInt const hiRange = (((cInt) 0x3FFFFFFF) << 32 | 0xFFFFFFFF); 106 | // ajb end 107 | #endif 108 | 109 | struct IntPoint { 110 | cInt X; 111 | cInt Y; 112 | #ifdef use_xyz 113 | cInt Z; 114 | IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {}; 115 | #else 116 | IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {}; 117 | #endif 118 | 119 | friend inline bool operator== (const IntPoint& a, const IntPoint& b) 120 | { 121 | return a.X == b.X && a.Y == b.Y; 122 | } 123 | friend inline bool operator!= (const IntPoint& a, const IntPoint& b) 124 | { 125 | return a.X != b.X || a.Y != b.Y; 126 | } 127 | }; 128 | //------------------------------------------------------------------------------ 129 | 130 | typedef std::vector< IntPoint > Path; 131 | typedef std::vector< Path > Paths; 132 | 133 | inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;} 134 | inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;} 135 | 136 | #ifndef R_PACKAGE 137 | std::ostream& operator <<(std::ostream &s, const IntPoint &p); 138 | std::ostream& operator <<(std::ostream &s, const Path &p); 139 | std::ostream& operator <<(std::ostream &s, const Paths &p); 140 | #endif 141 | 142 | struct DoublePoint 143 | { 144 | double X; 145 | double Y; 146 | DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {} 147 | DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {} 148 | }; 149 | //------------------------------------------------------------------------------ 150 | 151 | #ifdef use_xyz 152 | typedef void (*ZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt); 153 | #endif 154 | 155 | enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4}; 156 | enum JoinType {jtSquare, jtRound, jtMiter}; 157 | enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound}; 158 | 159 | class PolyNode; 160 | typedef std::vector< PolyNode* > PolyNodes; 161 | 162 | class PolyNode 163 | { 164 | public: 165 | PolyNode(); 166 | virtual ~PolyNode(){}; 167 | Path Contour; 168 | PolyNodes Childs; 169 | PolyNode* Parent; 170 | PolyNode* GetNext() const; 171 | bool IsHole() const; 172 | bool IsOpen() const; 173 | int ChildCount() const; 174 | private: 175 | unsigned Index; //node index in Parent.Childs 176 | bool m_IsOpen; 177 | JoinType m_jointype; 178 | EndType m_endtype; 179 | PolyNode* GetNextSiblingUp() const; 180 | void AddChild(PolyNode& child); 181 | friend class Clipper; //to access Index 182 | friend class ClipperOffset; 183 | }; 184 | 185 | class PolyTree: public PolyNode 186 | { 187 | public: 188 | ~PolyTree(){Clear();}; 189 | PolyNode* GetFirst() const; 190 | void Clear(); 191 | int Total() const; 192 | private: 193 | PolyNodes AllNodes; 194 | friend class Clipper; //to access AllNodes 195 | }; 196 | 197 | bool Orientation(const Path &poly); 198 | double Area(const Path &poly); 199 | int PointInPolygon(const IntPoint &pt, const Path &path); 200 | 201 | void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd); 202 | void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd); 203 | void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd); 204 | 205 | void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415); 206 | void CleanPolygon(Path& poly, double distance = 1.415); 207 | void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415); 208 | void CleanPolygons(Paths& polys, double distance = 1.415); 209 | 210 | void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed); 211 | void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed); 212 | void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution); 213 | 214 | void PolyTreeToPaths(const PolyTree& polytree, Paths& paths); 215 | void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths); 216 | void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths); 217 | 218 | void ReversePath(Path& p); 219 | void ReversePaths(Paths& p); 220 | 221 | struct IntRect { cInt left; cInt top; cInt right; cInt bottom; }; 222 | 223 | //enums that are used internally ... 224 | enum EdgeSide { esLeft = 1, esRight = 2}; 225 | 226 | //forward declarations (for stuff used internally) ... 227 | struct TEdge; 228 | struct IntersectNode; 229 | struct LocalMinimum; 230 | struct OutPt; 231 | struct OutRec; 232 | struct Join; 233 | 234 | typedef std::vector < OutRec* > PolyOutList; 235 | typedef std::vector < TEdge* > EdgeList; 236 | typedef std::vector < Join* > JoinList; 237 | typedef std::vector < IntersectNode* > IntersectList; 238 | 239 | //------------------------------------------------------------------------------ 240 | 241 | //ClipperBase is the ancestor to the Clipper class. It should not be 242 | //instantiated directly. This class simply abstracts the conversion of sets of 243 | //polygon coordinates into edge objects that are stored in a LocalMinima list. 244 | class ClipperBase 245 | { 246 | public: 247 | ClipperBase(); 248 | virtual ~ClipperBase(); 249 | virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed); 250 | bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed); 251 | virtual void Clear(); 252 | IntRect GetBounds(); 253 | bool PreserveCollinear() {return m_PreserveCollinear;}; 254 | void PreserveCollinear(bool value) {m_PreserveCollinear = value;}; 255 | protected: 256 | void DisposeLocalMinimaList(); 257 | TEdge* AddBoundsToLML(TEdge *e, bool IsClosed); 258 | virtual void Reset(); 259 | TEdge* ProcessBound(TEdge* E, bool IsClockwise); 260 | void InsertScanbeam(const cInt Y); 261 | bool PopScanbeam(cInt &Y); 262 | bool LocalMinimaPending(); 263 | bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin); 264 | OutRec* CreateOutRec(); 265 | void DisposeAllOutRecs(); 266 | void DisposeOutRec(PolyOutList::size_type index); 267 | void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2); 268 | void DeleteFromAEL(TEdge *e); 269 | void UpdateEdgeIntoAEL(TEdge *&e); 270 | 271 | typedef std::vector MinimaList; 272 | MinimaList::iterator m_CurrentLM; 273 | MinimaList m_MinimaList; 274 | 275 | bool m_UseFullRange; 276 | EdgeList m_edges; 277 | bool m_PreserveCollinear; 278 | bool m_HasOpenPaths; 279 | PolyOutList m_PolyOuts; 280 | TEdge *m_ActiveEdges; 281 | 282 | typedef std::priority_queue ScanbeamList; 283 | ScanbeamList m_Scanbeam; 284 | }; 285 | //------------------------------------------------------------------------------ 286 | 287 | class Clipper : public virtual ClipperBase 288 | { 289 | public: 290 | Clipper(int initOptions = 0); 291 | bool Execute(ClipType clipType, 292 | Paths &solution, 293 | PolyFillType fillType = pftEvenOdd); 294 | bool Execute(ClipType clipType, 295 | Paths &solution, 296 | PolyFillType subjFillType, 297 | PolyFillType clipFillType); 298 | bool Execute(ClipType clipType, 299 | PolyTree &polytree, 300 | PolyFillType fillType = pftEvenOdd); 301 | bool Execute(ClipType clipType, 302 | PolyTree &polytree, 303 | PolyFillType subjFillType, 304 | PolyFillType clipFillType); 305 | bool ReverseSolution() { return m_ReverseOutput; }; 306 | void ReverseSolution(bool value) {m_ReverseOutput = value;}; 307 | bool StrictlySimple() {return m_StrictSimple;}; 308 | void StrictlySimple(bool value) {m_StrictSimple = value;}; 309 | //set the callback function for z value filling on intersections (otherwise Z is 0) 310 | #ifdef use_xyz 311 | void ZFillFunction(ZFillCallback zFillFunc); 312 | #endif 313 | protected: 314 | virtual bool ExecuteInternal(); 315 | private: 316 | JoinList m_Joins; 317 | JoinList m_GhostJoins; 318 | IntersectList m_IntersectList; 319 | ClipType m_ClipType; 320 | typedef std::list MaximaList; 321 | MaximaList m_Maxima; 322 | TEdge *m_SortedEdges; 323 | bool m_ExecuteLocked; 324 | PolyFillType m_ClipFillType; 325 | PolyFillType m_SubjFillType; 326 | bool m_ReverseOutput; 327 | bool m_UsingPolyTree; 328 | bool m_StrictSimple; 329 | #ifdef use_xyz 330 | ZFillCallback m_ZFill; //custom callback 331 | #endif 332 | void SetWindingCount(TEdge& edge); 333 | bool IsEvenOddFillType(const TEdge& edge) const; 334 | bool IsEvenOddAltFillType(const TEdge& edge) const; 335 | void InsertLocalMinimaIntoAEL(const cInt botY); 336 | void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge); 337 | void AddEdgeToSEL(TEdge *edge); 338 | bool PopEdgeFromSEL(TEdge *&edge); 339 | void CopyAELToSEL(); 340 | void DeleteFromSEL(TEdge *e); 341 | void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2); 342 | bool IsContributing(const TEdge& edge) const; 343 | bool IsTopHorz(const cInt XPos); 344 | void DoMaxima(TEdge *e); 345 | void ProcessHorizontals(); 346 | void ProcessHorizontal(TEdge *horzEdge); 347 | void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); 348 | OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); 349 | OutRec* GetOutRec(int idx); 350 | void AppendPolygon(TEdge *e1, TEdge *e2); 351 | void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt); 352 | OutPt* AddOutPt(TEdge *e, const IntPoint &pt); 353 | OutPt* GetLastOutPt(TEdge *e); 354 | bool ProcessIntersections(const cInt topY); 355 | void BuildIntersectList(const cInt topY); 356 | void ProcessIntersectList(); 357 | void ProcessEdgesAtTopOfScanbeam(const cInt topY); 358 | void BuildResult(Paths& polys); 359 | void BuildResult2(PolyTree& polytree); 360 | void SetHoleState(TEdge *e, OutRec *outrec); 361 | void DisposeIntersectNodes(); 362 | bool FixupIntersectionOrder(); 363 | void FixupOutPolygon(OutRec &outrec); 364 | void FixupOutPolyline(OutRec &outrec); 365 | bool IsHole(TEdge *e); 366 | bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl); 367 | void FixHoleLinkage(OutRec &outrec); 368 | void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt); 369 | void ClearJoins(); 370 | void ClearGhostJoins(); 371 | void AddGhostJoin(OutPt *op, const IntPoint offPt); 372 | bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2); 373 | void JoinCommonEdges(); 374 | void DoSimplePolygons(); 375 | void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec); 376 | void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec); 377 | void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec); 378 | #ifdef use_xyz 379 | void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2); 380 | #endif 381 | }; 382 | //------------------------------------------------------------------------------ 383 | 384 | class ClipperOffset 385 | { 386 | public: 387 | ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25); 388 | ~ClipperOffset(); 389 | void AddPath(const Path& path, JoinType joinType, EndType endType); 390 | void AddPaths(const Paths& paths, JoinType joinType, EndType endType); 391 | void Execute(Paths& solution, double delta); 392 | void Execute(PolyTree& solution, double delta); 393 | void Clear(); 394 | double MiterLimit; 395 | double ArcTolerance; 396 | private: 397 | Paths m_destPolys; 398 | Path m_srcPoly; 399 | Path m_destPoly; 400 | std::vector m_normals; 401 | double m_delta, m_sinA, m_sin, m_cos; 402 | double m_miterLim, m_StepsPerRad; 403 | IntPoint m_lowest; 404 | PolyNode m_polyNodes; 405 | 406 | void FixOrientations(); 407 | void DoOffset(double delta); 408 | void OffsetPoint(int j, int& k, JoinType jointype); 409 | void DoSquare(int j, int k); 410 | void DoMiter(int j, int k, double r); 411 | void DoRound(int j, int k); 412 | }; 413 | //------------------------------------------------------------------------------ 414 | 415 | #ifndef R_PACKAGE 416 | class clipperException : public std::exception 417 | { 418 | public: 419 | clipperException(const char* description): m_descr(description) {} 420 | virtual ~clipperException() throw() {} 421 | virtual const char* what() const throw() {return m_descr.c_str();} 422 | private: 423 | std::string m_descr; 424 | }; 425 | #endif 426 | //------------------------------------------------------------------------------ 427 | 428 | } //ClipperLib namespace 429 | 430 | #endif //clipper_hpp 431 | 432 | 433 | -------------------------------------------------------------------------------- /src/interface.cpp: -------------------------------------------------------------------------------- 1 | #include "clipper.h" 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | using namespace ClipperLib; 7 | 8 | void CopyToPath(int *x, int *y, int n, ClipperLib::Path &p) 9 | { 10 | p.clear(); 11 | p.reserve(n); 12 | for (int i = 0; i < n; i++) 13 | p.push_back(IntPoint(x[i], y[i])); 14 | } 15 | 16 | void CopyFromPath(ClipperLib::Path &p, int *x, int *y, int nmax, int *n) 17 | { 18 | int N; 19 | *n = N = p.size(); 20 | if(N <= nmax) { 21 | for (int i = 0; i < N; i++) 22 | { 23 | x[i] = p[i].X; 24 | y[i] = p[i].Y; 25 | } 26 | } 27 | } 28 | 29 | void ScaleToPath(double *x, double *y, int n, ClipperLib::Path &p, 30 | double x0, double y0, double eps) 31 | { 32 | int i; 33 | cInt cxi, cyi; 34 | p.clear(); 35 | p.reserve(n); 36 | for (i = 0; i < n; i++) { 37 | cxi = (cInt) ((x[i] - x0)/eps); 38 | cyi = (cInt) ((y[i] - y0)/eps); 39 | p.push_back(IntPoint(cxi, cyi)); 40 | } 41 | } 42 | 43 | void ScaleFromPath(ClipperLib::Path &p, double *x, double *y, int nmax, int *n, 44 | double x0, double y0, double eps) 45 | { 46 | int N; 47 | *n = N = p.size(); 48 | if(N <= nmax) { 49 | for (int i = 0; i < N; i++) 50 | { 51 | x[i] = x0 + eps * ((double) p[i].X); 52 | y[i] = y0 + eps * ((double) p[i].Y); 53 | } 54 | } 55 | } 56 | 57 | extern "C" { 58 | SEXP Csimplify(SEXP A, 59 | SEXP pft, 60 | SEXP X0, 61 | SEXP Y0, 62 | SEXP Eps) { 63 | int nA, i, nAi, m, mi, mitrue; 64 | double *x, *y, *xx, *yy; 65 | SEXP Ai = R_NilValue; 66 | SEXP out, outi, xouti, youti; 67 | int pftcode; 68 | PolyFillType filltype; 69 | double x0, y0, eps; 70 | 71 | // protect arguments from garbage collector 72 | PROTECT(A = AS_LIST(A)); 73 | PROTECT(pft = AS_INTEGER(pft)); 74 | PROTECT(X0 = AS_NUMERIC(X0)); 75 | PROTECT(Y0 = AS_NUMERIC(Y0)); 76 | PROTECT(Eps = AS_NUMERIC(Eps)); 77 | // that's 5 arguments 78 | 79 | // number of polygons 80 | nA = LENGTH(A); 81 | 82 | // Initialise object containing n polygons 83 | Paths polyA(nA); 84 | 85 | // Get scale parameters 86 | x0 = *(NUMERIC_POINTER(X0)); 87 | y0 = *(NUMERIC_POINTER(Y0)); 88 | eps = *(NUMERIC_POINTER(Eps)); 89 | 90 | // copy data 91 | for(i = 0; i < nA; i++) { 92 | Ai = VECTOR_ELT(A, i); 93 | nAi = LENGTH(VECTOR_ELT(Ai, 0)); 94 | x = NUMERIC_POINTER(VECTOR_ELT(Ai, 0)); 95 | y = NUMERIC_POINTER(VECTOR_ELT(Ai, 1)); 96 | ScaleToPath(x, y, nAi, polyA[i], x0, y0, eps); 97 | } 98 | 99 | // interpret clipping parameters 100 | pftcode = *(INTEGER_POINTER(pft)); 101 | switch(pftcode) { 102 | case 1: 103 | filltype = pftEvenOdd; 104 | break; 105 | case 2: 106 | filltype = pftNonZero; 107 | break; 108 | case 3: 109 | filltype = pftPositive; 110 | break; 111 | case 4: 112 | filltype = pftNegative; 113 | break; 114 | default: 115 | error("polyclip: unrecognised code for fill type A"); 116 | } 117 | 118 | // simplify polygon; 119 | Paths result; 120 | SimplifyPolygons(polyA, result, filltype); 121 | 122 | // number of polygons 123 | m = result.size(); 124 | 125 | // initialise output list 126 | PROTECT(out = NEW_LIST(m)); 127 | 128 | // copy data 129 | if(m > 0) { 130 | for(i = 0; i < m; i++) { 131 | mi = result[i].size(); 132 | // Allocate space for output 133 | PROTECT(outi = NEW_LIST(2)); 134 | PROTECT(xouti = NEW_NUMERIC(mi)); 135 | PROTECT(youti = NEW_NUMERIC(mi)); 136 | xx = NUMERIC_POINTER(xouti); 137 | yy = NUMERIC_POINTER(youti); 138 | // copy to output space 139 | ScaleFromPath(result[i], xx, yy, mi, &mitrue, x0, y0, eps); 140 | // Put vectors into list 141 | SET_VECTOR_ELT(outi, 0, xouti); 142 | SET_VECTOR_ELT(outi, 1, youti); 143 | SET_VECTOR_ELT(out, i, outi); 144 | } 145 | } 146 | 147 | UNPROTECT(6 + 3*m); // 5 arguments + out + m * (outi, xouti, youti) 148 | return(out); 149 | } 150 | } 151 | 152 | // ----------------------------------------------------------------- 153 | 154 | extern "C" { 155 | SEXP Cclipbool(SEXP A, 156 | SEXP B, 157 | SEXP pftA, 158 | SEXP pftB, 159 | SEXP ct, 160 | SEXP X0, 161 | SEXP Y0, 162 | SEXP Eps 163 | ){ 164 | int nA, nB, i, n, m, mi, mitrue; 165 | double *x, *y, *xx, *yy; 166 | SEXP Ai = R_NilValue, Bi = R_NilValue; 167 | SEXP out, outi, xouti, youti; 168 | ClipType cliptype; 169 | PolyFillType filltypeA, filltypeB; 170 | int ctcode, pftAcode, pftBcode; 171 | double x0, y0, eps; 172 | 173 | // protect arguments from garbage collector 174 | PROTECT(A = AS_LIST(A)); 175 | PROTECT(B = AS_LIST(B)); 176 | PROTECT(ct = AS_INTEGER(ct)); 177 | PROTECT(pftA = AS_INTEGER(pftA)); 178 | PROTECT(pftB = AS_INTEGER(pftB)); 179 | PROTECT(X0 = AS_NUMERIC(X0)); 180 | PROTECT(Y0 = AS_NUMERIC(Y0)); 181 | PROTECT(Eps = AS_NUMERIC(Eps)); 182 | 183 | // lengths of lists 184 | nA = LENGTH(A); 185 | nB = LENGTH(B); 186 | 187 | // Initialise object containing n polygons 188 | Paths polyA(nA), polyB(nB); 189 | 190 | // Get scale parameters 191 | x0 = *(NUMERIC_POINTER(X0)); 192 | y0 = *(NUMERIC_POINTER(Y0)); 193 | eps = *(NUMERIC_POINTER(Eps)); 194 | 195 | // copy data 196 | for(i = 0; i < nA; i++) { 197 | Ai = VECTOR_ELT(A, i); 198 | n = LENGTH(VECTOR_ELT(Ai, 0)); 199 | x = NUMERIC_POINTER(VECTOR_ELT(Ai, 0)); 200 | y = NUMERIC_POINTER(VECTOR_ELT(Ai, 1)); 201 | ScaleToPath(x, y, n, polyA[i], x0, y0, eps); 202 | } 203 | for(i = 0; i < nB; i++) { 204 | Bi = VECTOR_ELT(B, i); 205 | n = LENGTH(VECTOR_ELT(Bi, 0)); 206 | x = NUMERIC_POINTER(VECTOR_ELT(Bi, 0)); 207 | y = NUMERIC_POINTER(VECTOR_ELT(Bi, 1)); 208 | ScaleToPath(x, y, n, polyB[i], x0, y0, eps); 209 | } 210 | 211 | // interpret clipping parameters 212 | ctcode = *(INTEGER_POINTER(ct)); 213 | pftAcode = *(INTEGER_POINTER(pftA)); 214 | pftBcode = *(INTEGER_POINTER(pftB)); 215 | switch(ctcode) { 216 | case 1: 217 | cliptype = ctIntersection; 218 | break; 219 | case 2: 220 | cliptype = ctUnion; 221 | break; 222 | case 3: 223 | cliptype = ctDifference; 224 | break; 225 | case 4: 226 | cliptype = ctXor; 227 | break; 228 | default: 229 | error("polyclip: unrecognised code for cliptype"); 230 | } 231 | switch(pftAcode) { 232 | case 1: 233 | filltypeA = pftEvenOdd; 234 | break; 235 | case 2: 236 | filltypeA = pftNonZero; 237 | break; 238 | case 3: 239 | filltypeA = pftPositive; 240 | break; 241 | case 4: 242 | filltypeA = pftNegative; 243 | break; 244 | default: 245 | error("polyclip: unrecognised code for fill type A"); 246 | } 247 | switch(pftBcode) { 248 | case 1: 249 | filltypeB = pftEvenOdd; 250 | break; 251 | case 2: 252 | filltypeB = pftNonZero; 253 | break; 254 | case 3: 255 | filltypeB = pftPositive; 256 | break; 257 | case 4: 258 | filltypeB = pftNegative; 259 | break; 260 | default: 261 | error("polyclip: unrecognised code for fill type B"); 262 | } 263 | 264 | // perform clipping operation 265 | Clipper c; 266 | Paths result; 267 | c.AddPaths(polyA, ptSubject, true); 268 | c.AddPaths(polyB, ptClip, true); 269 | c.Execute(cliptype, result, filltypeA, filltypeB); 270 | 271 | // number of polygons 272 | m = result.size(); 273 | 274 | // initialise output list 275 | PROTECT(out = NEW_LIST(m)); 276 | 277 | // copy data 278 | if(m > 0) { 279 | for(i = 0; i < m; i++) { 280 | mi = result[i].size(); 281 | // Allocate space for output 282 | PROTECT(outi = NEW_LIST(2)); 283 | PROTECT(xouti = NEW_NUMERIC(mi)); 284 | PROTECT(youti = NEW_NUMERIC(mi)); 285 | xx = NUMERIC_POINTER(xouti); 286 | yy = NUMERIC_POINTER(youti); 287 | // copy to output space 288 | ScaleFromPath(result[i], xx, yy, mi, &mitrue, x0, y0, eps); 289 | // Put vectors into list 290 | SET_VECTOR_ELT(outi, 0, xouti); 291 | SET_VECTOR_ELT(outi, 1, youti); 292 | SET_VECTOR_ELT(out, i, outi); 293 | } 294 | } 295 | 296 | UNPROTECT(9 + 3*m); // 8 arguments + out + m * (outi, xouti, youti) 297 | return(out); 298 | } 299 | } 300 | 301 | // offset (dilation) operation for closed polygons 302 | 303 | extern "C" { 304 | SEXP Cpolyoffset(SEXP A, 305 | SEXP del, 306 | SEXP jt, 307 | SEXP mlim, 308 | SEXP atol, 309 | SEXP X0, 310 | SEXP Y0, 311 | SEXP Eps 312 | ){ 313 | int nA, i, n, m, mi, mitrue; 314 | double *x, *y, *xx, *yy; 315 | SEXP Ai = R_NilValue; 316 | SEXP out, outi, xouti, youti; 317 | JoinType jointype; 318 | int jtcode; 319 | double delta, miterlimit, arctolerance; 320 | double x0, y0, eps; 321 | 322 | // protect arguments from garbage collector 323 | PROTECT(A = AS_LIST(A)); 324 | PROTECT(del = AS_NUMERIC(del)); 325 | PROTECT(jt = AS_INTEGER(jt)); 326 | PROTECT(mlim = AS_NUMERIC(mlim)); 327 | PROTECT(atol = AS_NUMERIC(atol)); 328 | PROTECT(X0 = AS_NUMERIC(X0)); 329 | PROTECT(Y0 = AS_NUMERIC(Y0)); 330 | PROTECT(Eps = AS_NUMERIC(Eps)); 331 | 332 | // length of list 333 | nA = LENGTH(A); 334 | 335 | // Initialise object containing nA polygons 336 | Paths polyA(nA); 337 | 338 | // Get scale parameters 339 | x0 = *(NUMERIC_POINTER(X0)); 340 | y0 = *(NUMERIC_POINTER(Y0)); 341 | eps = *(NUMERIC_POINTER(Eps)); 342 | 343 | // copy data 344 | for(i = 0; i < nA; i++) { 345 | Ai = VECTOR_ELT(A, i); 346 | n = LENGTH(VECTOR_ELT(Ai, 0)); 347 | x = NUMERIC_POINTER(VECTOR_ELT(Ai, 0)); 348 | y = NUMERIC_POINTER(VECTOR_ELT(Ai, 1)); 349 | ScaleToPath(x, y, n, polyA[i], x0, y0, eps); 350 | } 351 | 352 | // interpret offset parameters 353 | jtcode = *(INTEGER_POINTER(jt)); 354 | switch(jtcode) { 355 | case 1: 356 | jointype = jtSquare; 357 | break; 358 | case 2: 359 | jointype = jtRound; 360 | break; 361 | case 3: 362 | jointype = jtMiter; 363 | break; 364 | default: 365 | error("polyclip: unrecognised code for jointype"); 366 | } 367 | 368 | // get parameters 369 | delta = *(NUMERIC_POINTER(del)); // absolute distance 370 | miterlimit = *(NUMERIC_POINTER(mlim)); // multiple of 'delta' 371 | arctolerance = *(NUMERIC_POINTER(atol)); // absolute distance 372 | // rescale 373 | delta = delta/eps; 374 | arctolerance = arctolerance/eps; 375 | 376 | // perform offset operation 377 | ClipperOffset co; 378 | Paths result; 379 | co.AddPaths(polyA, jointype, etClosedPolygon); 380 | co.MiterLimit = miterlimit; 381 | co.ArcTolerance = arctolerance; 382 | co.Execute(result, delta); 383 | 384 | // number of polygons 385 | m = result.size(); 386 | 387 | // initialise output list 388 | PROTECT(out = NEW_LIST(m)); 389 | 390 | // copy data 391 | if(m > 0) { 392 | for(i = 0; i < m; i++) { 393 | mi = result[i].size(); 394 | // Allocate space for output 395 | PROTECT(outi = NEW_LIST(2)); 396 | PROTECT(xouti = NEW_NUMERIC(mi)); 397 | PROTECT(youti = NEW_NUMERIC(mi)); 398 | xx = NUMERIC_POINTER(xouti); 399 | yy = NUMERIC_POINTER(youti); 400 | // copy to output space 401 | ScaleFromPath(result[i], xx, yy, mi, &mitrue, x0, y0, eps); 402 | // Put vectors into list 403 | SET_VECTOR_ELT(outi, 0, xouti); 404 | SET_VECTOR_ELT(outi, 1, youti); 405 | SET_VECTOR_ELT(out, i, outi); 406 | } 407 | } 408 | 409 | UNPROTECT(9 + 3*m); // 8 arguments + out + m * (outi, xouti, youti) 410 | return(out); 411 | } 412 | } 413 | 414 | 415 | // offset (dilation) operation for polygonal lines 416 | 417 | extern "C" { 418 | SEXP Clineoffset(SEXP A, 419 | SEXP del, 420 | SEXP jt, 421 | SEXP et, 422 | SEXP mlim, 423 | SEXP atol, 424 | SEXP X0, 425 | SEXP Y0, 426 | SEXP Eps 427 | ){ 428 | int nA, i, n, m, mi, mitrue; 429 | double *x, *y, *xx, *yy; 430 | SEXP Ai = R_NilValue; 431 | SEXP out, outi, xouti, youti; 432 | JoinType jointype; 433 | EndType endtype; 434 | int jtcode, etcode; 435 | double delta, miterlimit, arctolerance; 436 | double x0, y0, eps; 437 | 438 | // protect arguments from garbage collector 439 | PROTECT(A = AS_LIST(A)); 440 | PROTECT(del = AS_NUMERIC(del)); 441 | PROTECT(jt = AS_INTEGER(jt)); 442 | PROTECT(et = AS_INTEGER(et)); 443 | PROTECT(mlim = AS_NUMERIC(mlim)); 444 | PROTECT(atol = AS_NUMERIC(atol)); 445 | PROTECT(X0 = AS_NUMERIC(X0)); 446 | PROTECT(Y0 = AS_NUMERIC(Y0)); 447 | PROTECT(Eps = AS_NUMERIC(Eps)); 448 | 449 | // length of list 450 | nA = LENGTH(A); 451 | 452 | // Initialise object containing nA polygonal lines 453 | Paths polyA(nA); 454 | 455 | // Get scale parameters 456 | x0 = *(NUMERIC_POINTER(X0)); 457 | y0 = *(NUMERIC_POINTER(Y0)); 458 | eps = *(NUMERIC_POINTER(Eps)); 459 | 460 | // copy data 461 | for(i = 0; i < nA; i++) { 462 | Ai = VECTOR_ELT(A, i); 463 | n = LENGTH(VECTOR_ELT(Ai, 0)); 464 | x = NUMERIC_POINTER(VECTOR_ELT(Ai, 0)); 465 | y = NUMERIC_POINTER(VECTOR_ELT(Ai, 1)); 466 | ScaleToPath(x, y, n, polyA[i], x0, y0, eps); 467 | } 468 | 469 | // interpret offset parameters 470 | jtcode = *(INTEGER_POINTER(jt)); 471 | switch(jtcode) { 472 | case 1: 473 | jointype = jtSquare; 474 | break; 475 | case 2: 476 | jointype = jtRound; 477 | break; 478 | case 3: 479 | jointype = jtMiter; 480 | break; 481 | default: 482 | error("polyclip: unrecognised code for jointype"); 483 | } 484 | etcode = *(INTEGER_POINTER(et)); 485 | switch(etcode) { 486 | case 1: 487 | endtype = etClosedPolygon; 488 | break; 489 | case 2: 490 | endtype = etClosedLine; 491 | break; 492 | case 3: 493 | endtype = etOpenButt; 494 | break; 495 | case 4: 496 | endtype = etOpenSquare; 497 | break; 498 | case 5: 499 | endtype = etOpenRound; 500 | break; 501 | default: 502 | error("polyclip: unrecognised code for endtype"); 503 | } 504 | 505 | // get parameters 506 | delta = *(NUMERIC_POINTER(del)); // absolute distance 507 | miterlimit = *(NUMERIC_POINTER(mlim)); // multiple of 'delta' 508 | arctolerance = *(NUMERIC_POINTER(atol)); // absolute distance 509 | // rescale 510 | delta = delta/eps; 511 | arctolerance = arctolerance/eps; 512 | 513 | // perform offset operation 514 | ClipperOffset co; 515 | Paths result; 516 | co.AddPaths(polyA, jointype, endtype); 517 | co.MiterLimit = miterlimit; 518 | co.ArcTolerance = arctolerance; 519 | co.Execute(result, delta); 520 | 521 | // number of polygons 522 | m = result.size(); 523 | 524 | // initialise output list 525 | PROTECT(out = NEW_LIST(m)); 526 | 527 | // copy data 528 | if(m > 0) { 529 | for(i = 0; i < m; i++) { 530 | mi = result[i].size(); 531 | // Allocate space for output 532 | PROTECT(outi = NEW_LIST(2)); 533 | PROTECT(xouti = NEW_NUMERIC(mi)); 534 | PROTECT(youti = NEW_NUMERIC(mi)); 535 | xx = NUMERIC_POINTER(xouti); 536 | yy = NUMERIC_POINTER(youti); 537 | // copy to output space 538 | ScaleFromPath(result[i], xx, yy, mi, &mitrue, x0, y0, eps); 539 | // Put vectors into list 540 | SET_VECTOR_ELT(outi, 0, xouti); 541 | SET_VECTOR_ELT(outi, 1, youti); 542 | SET_VECTOR_ELT(out, i, outi); 543 | } 544 | } 545 | 546 | UNPROTECT(10 + 3*m); // 9 arguments + out + m * (outi, xouti, youti) 547 | return(out); 548 | } 549 | } 550 | 551 | // Minkowski sum of polygon with **path(s)** 552 | 553 | extern "C" { 554 | SEXP Cminksum(SEXP A, // list(list(x,y)) : polygon 555 | SEXP B, // list(list(x,y), list(x,y), ....) 556 | SEXP clo, // whether paths in B are closed 557 | SEXP X0, 558 | SEXP Y0, 559 | SEXP Eps) { 560 | int nB, i, nBi, nA0, m, mi, mitrue; 561 | double *x, *y, *xx, *yy; 562 | SEXP A0 = R_NilValue; 563 | SEXP Bi = R_NilValue; 564 | SEXP out, outi, xouti, youti; 565 | bool closed; 566 | double x0, y0, eps; 567 | Path pathA; 568 | 569 | // protect arguments from garbage collector 570 | PROTECT(A = AS_LIST(A)); 571 | PROTECT(B = AS_LIST(B)); 572 | PROTECT(clo = AS_LOGICAL(clo)); 573 | PROTECT(X0 = AS_NUMERIC(X0)); 574 | PROTECT(Y0 = AS_NUMERIC(Y0)); 575 | PROTECT(Eps = AS_NUMERIC(Eps)); 576 | // that's 6 arguments 577 | 578 | // Get scale parameters 579 | x0 = *(NUMERIC_POINTER(X0)); 580 | y0 = *(NUMERIC_POINTER(Y0)); 581 | eps = *(NUMERIC_POINTER(Eps)); 582 | 583 | // logical value specifying whether paths in B should be closed 584 | closed = *(LOGICAL_POINTER(clo)); 585 | 586 | // copy data from A 587 | A0 = VECTOR_ELT(A, 0); 588 | nA0 = LENGTH(VECTOR_ELT(A0, 0)); 589 | x = NUMERIC_POINTER(VECTOR_ELT(A0, 0)); 590 | y = NUMERIC_POINTER(VECTOR_ELT(A0, 1)); 591 | ScaleToPath(x, y, nA0, pathA, x0, y0, eps); 592 | 593 | // number of polygons in B 594 | nB = LENGTH(B); 595 | // Initialise object representing nB polygons 596 | Paths pathsB(nB); 597 | 598 | // copy data from B 599 | for(i = 0; i < nB; i++) { 600 | Bi = VECTOR_ELT(B, i); 601 | nBi = LENGTH(VECTOR_ELT(Bi, 0)); 602 | x = NUMERIC_POINTER(VECTOR_ELT(Bi, 0)); 603 | y = NUMERIC_POINTER(VECTOR_ELT(Bi, 1)); 604 | ScaleToPath(x, y, nBi, pathsB[i], x0, y0, eps); 605 | } 606 | 607 | // hit it 608 | Paths result; 609 | MinkowskiSum(pathA, pathsB, result, closed); 610 | 611 | // number of polygons 612 | m = result.size(); 613 | 614 | // initialise output list 615 | PROTECT(out = NEW_LIST(m)); 616 | 617 | // adjust origin: (x0,y0) were subtracted from both A and B 618 | x0 = 2.0 * x0; 619 | y0 = 2.0 * y0; 620 | 621 | // copy data 622 | if(m > 0) { 623 | for(i = 0; i < m; i++) { 624 | mi = result[i].size(); 625 | // Allocate space for output 626 | PROTECT(outi = NEW_LIST(2)); 627 | PROTECT(xouti = NEW_NUMERIC(mi)); 628 | PROTECT(youti = NEW_NUMERIC(mi)); 629 | xx = NUMERIC_POINTER(xouti); 630 | yy = NUMERIC_POINTER(youti); 631 | // copy to output space 632 | ScaleFromPath(result[i], xx, yy, mi, &mitrue, x0, y0, eps); 633 | // Put vectors into list 634 | SET_VECTOR_ELT(outi, 0, xouti); 635 | SET_VECTOR_ELT(outi, 1, youti); 636 | SET_VECTOR_ELT(out, i, outi); 637 | } 638 | } 639 | 640 | UNPROTECT(7 + 3*m); // 6 arguments + out + m * (outi, xouti, youti) 641 | return(out); 642 | } 643 | } 644 | -------------------------------------------------------------------------------- /config.status: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # Generated by configure. 3 | # Run this file to recreate the current configuration. 4 | # Compiler output produced by configure, useful for debugging 5 | # configure, is in config.log if it exists. 6 | 7 | debug=false 8 | ac_cs_recheck=false 9 | ac_cs_silent=false 10 | 11 | SHELL=${CONFIG_SHELL-/bin/bash} 12 | export SHELL 13 | ## -------------------- ## 14 | ## M4sh Initialization. ## 15 | ## -------------------- ## 16 | 17 | # Be more Bourne compatible 18 | DUALCASE=1; export DUALCASE # for MKS sh 19 | if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : 20 | emulate sh 21 | NULLCMD=: 22 | # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which 23 | # is contrary to our usage. Disable this feature. 24 | alias -g '${1+"$@"}'='"$@"' 25 | setopt NO_GLOB_SUBST 26 | else 27 | case `(set -o) 2>/dev/null` in #( 28 | *posix*) : 29 | set -o posix ;; #( 30 | *) : 31 | ;; 32 | esac 33 | fi 34 | 35 | 36 | as_nl=' 37 | ' 38 | export as_nl 39 | # Printing a long string crashes Solaris 7 /usr/bin/printf. 40 | as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' 41 | as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo 42 | as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo 43 | # Prefer a ksh shell builtin over an external printf program on Solaris, 44 | # but without wasting forks for bash or zsh. 45 | if test -z "$BASH_VERSION$ZSH_VERSION" \ 46 | && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then 47 | as_echo='print -r --' 48 | as_echo_n='print -rn --' 49 | elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then 50 | as_echo='printf %s\n' 51 | as_echo_n='printf %s' 52 | else 53 | if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then 54 | as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' 55 | as_echo_n='/usr/ucb/echo -n' 56 | else 57 | as_echo_body='eval expr "X$1" : "X\\(.*\\)"' 58 | as_echo_n_body='eval 59 | arg=$1; 60 | case $arg in #( 61 | *"$as_nl"*) 62 | expr "X$arg" : "X\\(.*\\)$as_nl"; 63 | arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; 64 | esac; 65 | expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" 66 | ' 67 | export as_echo_n_body 68 | as_echo_n='sh -c $as_echo_n_body as_echo' 69 | fi 70 | export as_echo_body 71 | as_echo='sh -c $as_echo_body as_echo' 72 | fi 73 | 74 | # The user is always right. 75 | if test "${PATH_SEPARATOR+set}" != set; then 76 | PATH_SEPARATOR=: 77 | (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { 78 | (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || 79 | PATH_SEPARATOR=';' 80 | } 81 | fi 82 | 83 | 84 | # IFS 85 | # We need space, tab and new line, in precisely that order. Quoting is 86 | # there to prevent editors from complaining about space-tab. 87 | # (If _AS_PATH_WALK were called with IFS unset, it would disable word 88 | # splitting by setting IFS to empty value.) 89 | IFS=" "" $as_nl" 90 | 91 | # Find who we are. Look in the path if we contain no directory separator. 92 | as_myself= 93 | case $0 in #(( 94 | *[\\/]* ) as_myself=$0 ;; 95 | *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR 96 | for as_dir in $PATH 97 | do 98 | IFS=$as_save_IFS 99 | test -z "$as_dir" && as_dir=. 100 | test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break 101 | done 102 | IFS=$as_save_IFS 103 | 104 | ;; 105 | esac 106 | # We did not find ourselves, most probably we were run as `sh COMMAND' 107 | # in which case we are not to be found in the path. 108 | if test "x$as_myself" = x; then 109 | as_myself=$0 110 | fi 111 | if test ! -f "$as_myself"; then 112 | $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 113 | exit 1 114 | fi 115 | 116 | # Unset variables that we do not need and which cause bugs (e.g. in 117 | # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" 118 | # suppresses any "Segmentation fault" message there. '((' could 119 | # trigger a bug in pdksh 5.2.14. 120 | for as_var in BASH_ENV ENV MAIL MAILPATH 121 | do eval test x\${$as_var+set} = xset \ 122 | && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : 123 | done 124 | PS1='$ ' 125 | PS2='> ' 126 | PS4='+ ' 127 | 128 | # NLS nuisances. 129 | LC_ALL=C 130 | export LC_ALL 131 | LANGUAGE=C 132 | export LANGUAGE 133 | 134 | # CDPATH. 135 | (unset CDPATH) >/dev/null 2>&1 && unset CDPATH 136 | 137 | 138 | # as_fn_error STATUS ERROR [LINENO LOG_FD] 139 | # ---------------------------------------- 140 | # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are 141 | # provided, also output the error to LOG_FD, referencing LINENO. Then exit the 142 | # script with STATUS, using 1 if that was 0. 143 | as_fn_error () 144 | { 145 | as_status=$1; test $as_status -eq 0 && as_status=1 146 | if test "$4"; then 147 | as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack 148 | $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 149 | fi 150 | $as_echo "$as_me: error: $2" >&2 151 | as_fn_exit $as_status 152 | } # as_fn_error 153 | 154 | 155 | # as_fn_set_status STATUS 156 | # ----------------------- 157 | # Set $? to STATUS, without forking. 158 | as_fn_set_status () 159 | { 160 | return $1 161 | } # as_fn_set_status 162 | 163 | # as_fn_exit STATUS 164 | # ----------------- 165 | # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. 166 | as_fn_exit () 167 | { 168 | set +e 169 | as_fn_set_status $1 170 | exit $1 171 | } # as_fn_exit 172 | 173 | # as_fn_unset VAR 174 | # --------------- 175 | # Portably unset VAR. 176 | as_fn_unset () 177 | { 178 | { eval $1=; unset $1;} 179 | } 180 | as_unset=as_fn_unset 181 | # as_fn_append VAR VALUE 182 | # ---------------------- 183 | # Append the text in VALUE to the end of the definition contained in VAR. Take 184 | # advantage of any shell optimizations that allow amortized linear growth over 185 | # repeated appends, instead of the typical quadratic growth present in naive 186 | # implementations. 187 | if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : 188 | eval 'as_fn_append () 189 | { 190 | eval $1+=\$2 191 | }' 192 | else 193 | as_fn_append () 194 | { 195 | eval $1=\$$1\$2 196 | } 197 | fi # as_fn_append 198 | 199 | # as_fn_arith ARG... 200 | # ------------------ 201 | # Perform arithmetic evaluation on the ARGs, and store the result in the 202 | # global $as_val. Take advantage of shells that can avoid forks. The arguments 203 | # must be portable across $(()) and expr. 204 | if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : 205 | eval 'as_fn_arith () 206 | { 207 | as_val=$(( $* )) 208 | }' 209 | else 210 | as_fn_arith () 211 | { 212 | as_val=`expr "$@" || test $? -eq 1` 213 | } 214 | fi # as_fn_arith 215 | 216 | 217 | if expr a : '\(a\)' >/dev/null 2>&1 && 218 | test "X`expr 00001 : '.*\(...\)'`" = X001; then 219 | as_expr=expr 220 | else 221 | as_expr=false 222 | fi 223 | 224 | if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then 225 | as_basename=basename 226 | else 227 | as_basename=false 228 | fi 229 | 230 | if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then 231 | as_dirname=dirname 232 | else 233 | as_dirname=false 234 | fi 235 | 236 | as_me=`$as_basename -- "$0" || 237 | $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ 238 | X"$0" : 'X\(//\)$' \| \ 239 | X"$0" : 'X\(/\)' \| . 2>/dev/null || 240 | $as_echo X/"$0" | 241 | sed '/^.*\/\([^/][^/]*\)\/*$/{ 242 | s//\1/ 243 | q 244 | } 245 | /^X\/\(\/\/\)$/{ 246 | s//\1/ 247 | q 248 | } 249 | /^X\/\(\/\).*/{ 250 | s//\1/ 251 | q 252 | } 253 | s/.*/./; q'` 254 | 255 | # Avoid depending upon Character Ranges. 256 | as_cr_letters='abcdefghijklmnopqrstuvwxyz' 257 | as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' 258 | as_cr_Letters=$as_cr_letters$as_cr_LETTERS 259 | as_cr_digits='0123456789' 260 | as_cr_alnum=$as_cr_Letters$as_cr_digits 261 | 262 | ECHO_C= ECHO_N= ECHO_T= 263 | case `echo -n x` in #((((( 264 | -n*) 265 | case `echo 'xy\c'` in 266 | *c*) ECHO_T=' ';; # ECHO_T is single tab character. 267 | xy) ECHO_C='\c';; 268 | *) echo `echo ksh88 bug on AIX 6.1` > /dev/null 269 | ECHO_T=' ';; 270 | esac;; 271 | *) 272 | ECHO_N='-n';; 273 | esac 274 | 275 | rm -f conf$$ conf$$.exe conf$$.file 276 | if test -d conf$$.dir; then 277 | rm -f conf$$.dir/conf$$.file 278 | else 279 | rm -f conf$$.dir 280 | mkdir conf$$.dir 2>/dev/null 281 | fi 282 | if (echo >conf$$.file) 2>/dev/null; then 283 | if ln -s conf$$.file conf$$ 2>/dev/null; then 284 | as_ln_s='ln -s' 285 | # ... but there are two gotchas: 286 | # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. 287 | # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. 288 | # In both cases, we have to default to `cp -pR'. 289 | ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || 290 | as_ln_s='cp -pR' 291 | elif ln conf$$.file conf$$ 2>/dev/null; then 292 | as_ln_s=ln 293 | else 294 | as_ln_s='cp -pR' 295 | fi 296 | else 297 | as_ln_s='cp -pR' 298 | fi 299 | rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file 300 | rmdir conf$$.dir 2>/dev/null 301 | 302 | 303 | # as_fn_mkdir_p 304 | # ------------- 305 | # Create "$as_dir" as a directory, including parents if necessary. 306 | as_fn_mkdir_p () 307 | { 308 | 309 | case $as_dir in #( 310 | -*) as_dir=./$as_dir;; 311 | esac 312 | test -d "$as_dir" || eval $as_mkdir_p || { 313 | as_dirs= 314 | while :; do 315 | case $as_dir in #( 316 | *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( 317 | *) as_qdir=$as_dir;; 318 | esac 319 | as_dirs="'$as_qdir' $as_dirs" 320 | as_dir=`$as_dirname -- "$as_dir" || 321 | $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ 322 | X"$as_dir" : 'X\(//\)[^/]' \| \ 323 | X"$as_dir" : 'X\(//\)$' \| \ 324 | X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || 325 | $as_echo X"$as_dir" | 326 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ 327 | s//\1/ 328 | q 329 | } 330 | /^X\(\/\/\)[^/].*/{ 331 | s//\1/ 332 | q 333 | } 334 | /^X\(\/\/\)$/{ 335 | s//\1/ 336 | q 337 | } 338 | /^X\(\/\).*/{ 339 | s//\1/ 340 | q 341 | } 342 | s/.*/./; q'` 343 | test -d "$as_dir" && break 344 | done 345 | test -z "$as_dirs" || eval "mkdir $as_dirs" 346 | } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" 347 | 348 | 349 | } # as_fn_mkdir_p 350 | if mkdir -p . 2>/dev/null; then 351 | as_mkdir_p='mkdir -p "$as_dir"' 352 | else 353 | test -d ./-p && rmdir ./-p 354 | as_mkdir_p=false 355 | fi 356 | 357 | 358 | # as_fn_executable_p FILE 359 | # ----------------------- 360 | # Test if FILE is an executable regular file. 361 | as_fn_executable_p () 362 | { 363 | test -f "$1" && test -x "$1" 364 | } # as_fn_executable_p 365 | as_test_x='test -x' 366 | as_executable_p=as_fn_executable_p 367 | 368 | # Sed expression to map a string onto a valid CPP name. 369 | as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" 370 | 371 | # Sed expression to map a string onto a valid variable name. 372 | as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" 373 | 374 | 375 | exec 6>&1 376 | ## ----------------------------------- ## 377 | ## Main body of $CONFIG_STATUS script. ## 378 | ## ----------------------------------- ## 379 | # Save the log message, to keep $0 and so on meaningful, and to 380 | # report actual input values of CONFIG_FILES etc. instead of their 381 | # values after options handling. 382 | ac_log=" 383 | This file was extended by polyclip $as_me 1.1-0, which was 384 | generated by GNU Autoconf 2.69. Invocation command line was 385 | 386 | CONFIG_FILES = $CONFIG_FILES 387 | CONFIG_HEADERS = $CONFIG_HEADERS 388 | CONFIG_LINKS = $CONFIG_LINKS 389 | CONFIG_COMMANDS = $CONFIG_COMMANDS 390 | $ $0 $@ 391 | 392 | on `(hostname || uname -n) 2>/dev/null | sed 1q` 393 | " 394 | 395 | # Files that config.status was made for. 396 | config_files=" src/Makevars" 397 | 398 | ac_cs_usage="\ 399 | \`$as_me' instantiates files and other configuration actions 400 | from templates according to the current configuration. Unless the files 401 | and actions are specified as TAGs, all are instantiated by default. 402 | 403 | Usage: $0 [OPTION]... [TAG]... 404 | 405 | -h, --help print this help, then exit 406 | -V, --version print version number and configuration settings, then exit 407 | --config print configuration, then exit 408 | -q, --quiet, --silent 409 | do not print progress messages 410 | -d, --debug don't remove temporary files 411 | --recheck update $as_me by reconfiguring in the same conditions 412 | --file=FILE[:TEMPLATE] 413 | instantiate the configuration file FILE 414 | 415 | Configuration files: 416 | $config_files 417 | 418 | Report bugs to the package provider." 419 | 420 | ac_cs_config="" 421 | ac_cs_version="\ 422 | polyclip config.status 1.1-0 423 | configured by ./configure, generated by GNU Autoconf 2.69, 424 | with options \"$ac_cs_config\" 425 | 426 | Copyright (C) 2012 Free Software Foundation, Inc. 427 | This config.status script is free software; the Free Software Foundation 428 | gives unlimited permission to copy, distribute and modify it." 429 | 430 | ac_pwd='/home/adrian/src/original/polyclip/distrib/polyclip' 431 | srcdir='.' 432 | test -n "$AWK" || AWK=awk 433 | # The default lists apply if the user does not specify any file. 434 | ac_need_defaults=: 435 | while test $# != 0 436 | do 437 | case $1 in 438 | --*=?*) 439 | ac_option=`expr "X$1" : 'X\([^=]*\)='` 440 | ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` 441 | ac_shift=: 442 | ;; 443 | --*=) 444 | ac_option=`expr "X$1" : 'X\([^=]*\)='` 445 | ac_optarg= 446 | ac_shift=: 447 | ;; 448 | *) 449 | ac_option=$1 450 | ac_optarg=$2 451 | ac_shift=shift 452 | ;; 453 | esac 454 | 455 | case $ac_option in 456 | # Handling of the options. 457 | -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) 458 | ac_cs_recheck=: ;; 459 | --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) 460 | $as_echo "$ac_cs_version"; exit ;; 461 | --config | --confi | --conf | --con | --co | --c ) 462 | $as_echo "$ac_cs_config"; exit ;; 463 | --debug | --debu | --deb | --de | --d | -d ) 464 | debug=: ;; 465 | --file | --fil | --fi | --f ) 466 | $ac_shift 467 | case $ac_optarg in 468 | *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; 469 | '') as_fn_error $? "missing file argument" ;; 470 | esac 471 | as_fn_append CONFIG_FILES " '$ac_optarg'" 472 | ac_need_defaults=false;; 473 | --he | --h | --help | --hel | -h ) 474 | $as_echo "$ac_cs_usage"; exit ;; 475 | -q | -quiet | --quiet | --quie | --qui | --qu | --q \ 476 | | -silent | --silent | --silen | --sile | --sil | --si | --s) 477 | ac_cs_silent=: ;; 478 | 479 | # This is an error. 480 | -*) as_fn_error $? "unrecognized option: \`$1' 481 | Try \`$0 --help' for more information." ;; 482 | 483 | *) as_fn_append ac_config_targets " $1" 484 | ac_need_defaults=false ;; 485 | 486 | esac 487 | shift 488 | done 489 | 490 | ac_configure_extra_args= 491 | 492 | if $ac_cs_silent; then 493 | exec 6>/dev/null 494 | ac_configure_extra_args="$ac_configure_extra_args --silent" 495 | fi 496 | 497 | if $ac_cs_recheck; then 498 | set X /bin/bash './configure' $ac_configure_extra_args --no-create --no-recursion 499 | shift 500 | $as_echo "running CONFIG_SHELL=/bin/bash $*" >&6 501 | CONFIG_SHELL='/bin/bash' 502 | export CONFIG_SHELL 503 | exec "$@" 504 | fi 505 | 506 | exec 5>>config.log 507 | { 508 | echo 509 | sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX 510 | ## Running $as_me. ## 511 | _ASBOX 512 | $as_echo "$ac_log" 513 | } >&5 514 | 515 | 516 | # Handling of arguments. 517 | for ac_config_target in $ac_config_targets 518 | do 519 | case $ac_config_target in 520 | "src/Makevars") CONFIG_FILES="$CONFIG_FILES src/Makevars" ;; 521 | 522 | *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; 523 | esac 524 | done 525 | 526 | 527 | # If the user did not use the arguments to specify the items to instantiate, 528 | # then the envvar interface is used. Set only those that are not. 529 | # We use the long form for the default assignment because of an extremely 530 | # bizarre bug on SunOS 4.1.3. 531 | if $ac_need_defaults; then 532 | test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files 533 | fi 534 | 535 | # Have a temporary directory for convenience. Make it in the build tree 536 | # simply because there is no reason against having it here, and in addition, 537 | # creating and moving files from /tmp can sometimes cause problems. 538 | # Hook for its removal unless debugging. 539 | # Note that there is a small window in which the directory will not be cleaned: 540 | # after its creation but before its name has been assigned to `$tmp'. 541 | $debug || 542 | { 543 | tmp= ac_tmp= 544 | trap 'exit_status=$? 545 | : "${ac_tmp:=$tmp}" 546 | { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status 547 | ' 0 548 | trap 'as_fn_exit 1' 1 2 13 15 549 | } 550 | # Create a (secure) tmp directory for tmp files. 551 | 552 | { 553 | tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && 554 | test -d "$tmp" 555 | } || 556 | { 557 | tmp=./conf$$-$RANDOM 558 | (umask 077 && mkdir "$tmp") 559 | } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 560 | ac_tmp=$tmp 561 | 562 | # Set up the scripts for CONFIG_FILES section. 563 | # No need to generate them if there are no CONFIG_FILES. 564 | # This happens for instance with `./config.status config.h'. 565 | if test -n "$CONFIG_FILES"; then 566 | 567 | 568 | ac_cr=`echo X | tr X '\015'` 569 | # On cygwin, bash can eat \r inside `` if the user requested igncr. 570 | # But we know of no other shell where ac_cr would be empty at this 571 | # point, so we can use a bashism as a fallback. 572 | if test "x$ac_cr" = x; then 573 | eval ac_cr=\$\'\\r\' 574 | fi 575 | ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` 576 | if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then 577 | ac_cs_awk_cr='\\r' 578 | else 579 | ac_cs_awk_cr=$ac_cr 580 | fi 581 | 582 | echo 'BEGIN {' >"$ac_tmp/subs1.awk" && 583 | cat >>"$ac_tmp/subs1.awk" <<\_ACAWK && 584 | S["LTLIBOBJS"]="" 585 | S["LIBOBJS"]="" 586 | S["POLYCLIP_CPPFLAGS"]="-DPOLYCLIP_LONG64=\"int64_t\" -DPOLYCLIP_ULONG64=\"uint64_t\"" 587 | S["EGREP"]="" 588 | S["GREP"]="" 589 | S["CXXCPP"]="" 590 | S["OBJEXT"]="o" 591 | S["EXEEXT"]="" 592 | S["ac_ct_CXX"]="g++" 593 | S["CPPFLAGS"]="" 594 | S["LDFLAGS"]="" 595 | S["CXXFLAGS"]="" 596 | S["CXX"]="g++" 597 | S["target_alias"]="" 598 | S["host_alias"]="" 599 | S["build_alias"]="" 600 | S["LIBS"]="" 601 | S["ECHO_T"]="" 602 | S["ECHO_N"]="-n" 603 | S["ECHO_C"]="" 604 | S["DEFS"]="-DPACKAGE_NAME=\\\"polyclip\\\" -DPACKAGE_TARNAME=\\\"polyclip\\\" -DPACKAGE_VERSION=\\\"1.1-0\\\" -DPACKAGE_STRING=\\\"polyclip\\ 1.1-0\\\" -DPACKAGE_BUGREPORT=\\\"\\\""\ 605 | " -DPACKAGE_URL=\\\"\\\" -DHAVE_INT64_T=1 -DHAVE_UINT64_T=1" 606 | S["mandir"]="${datarootdir}/man" 607 | S["localedir"]="${datarootdir}/locale" 608 | S["libdir"]="${exec_prefix}/lib" 609 | S["psdir"]="${docdir}" 610 | S["pdfdir"]="${docdir}" 611 | S["dvidir"]="${docdir}" 612 | S["htmldir"]="${docdir}" 613 | S["infodir"]="${datarootdir}/info" 614 | S["docdir"]="${datarootdir}/doc/${PACKAGE_TARNAME}" 615 | S["oldincludedir"]="/usr/include" 616 | S["includedir"]="${prefix}/include" 617 | S["localstatedir"]="${prefix}/var" 618 | S["sharedstatedir"]="${prefix}/com" 619 | S["sysconfdir"]="${prefix}/etc" 620 | S["datadir"]="${datarootdir}" 621 | S["datarootdir"]="${prefix}/share" 622 | S["libexecdir"]="${exec_prefix}/libexec" 623 | S["sbindir"]="${exec_prefix}/sbin" 624 | S["bindir"]="${exec_prefix}/bin" 625 | S["program_transform_name"]="s,x,x," 626 | S["prefix"]="/usr/local" 627 | S["exec_prefix"]="${prefix}" 628 | S["PACKAGE_URL"]="" 629 | S["PACKAGE_BUGREPORT"]="" 630 | S["PACKAGE_STRING"]="polyclip 1.1-0" 631 | S["PACKAGE_VERSION"]="1.1-0" 632 | S["PACKAGE_TARNAME"]="polyclip" 633 | S["PACKAGE_NAME"]="polyclip" 634 | S["PATH_SEPARATOR"]=":" 635 | S["SHELL"]="/bin/bash" 636 | _ACAWK 637 | cat >>"$ac_tmp/subs1.awk" <<_ACAWK && 638 | for (key in S) S_is_set[key] = 1 639 | FS = "" 640 | 641 | } 642 | { 643 | line = $ 0 644 | nfields = split(line, field, "@") 645 | substed = 0 646 | len = length(field[1]) 647 | for (i = 2; i < nfields; i++) { 648 | key = field[i] 649 | keylen = length(key) 650 | if (S_is_set[key]) { 651 | value = S[key] 652 | line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) 653 | len += length(value) + length(field[++i]) 654 | substed = 1 655 | } else 656 | len += 1 + keylen 657 | } 658 | 659 | print line 660 | } 661 | 662 | _ACAWK 663 | if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then 664 | sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" 665 | else 666 | cat 667 | fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ 668 | || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 669 | fi # test -n "$CONFIG_FILES" 670 | 671 | 672 | eval set X " :F $CONFIG_FILES " 673 | shift 674 | for ac_tag 675 | do 676 | case $ac_tag in 677 | :[FHLC]) ac_mode=$ac_tag; continue;; 678 | esac 679 | case $ac_mode$ac_tag in 680 | :[FHL]*:*);; 681 | :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; 682 | :[FH]-) ac_tag=-:-;; 683 | :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; 684 | esac 685 | ac_save_IFS=$IFS 686 | IFS=: 687 | set x $ac_tag 688 | IFS=$ac_save_IFS 689 | shift 690 | ac_file=$1 691 | shift 692 | 693 | case $ac_mode in 694 | :L) ac_source=$1;; 695 | :[FH]) 696 | ac_file_inputs= 697 | for ac_f 698 | do 699 | case $ac_f in 700 | -) ac_f="$ac_tmp/stdin";; 701 | *) # Look for the file first in the build tree, then in the source tree 702 | # (if the path is not absolute). The absolute path cannot be DOS-style, 703 | # because $ac_f cannot contain `:'. 704 | test -f "$ac_f" || 705 | case $ac_f in 706 | [\\/$]*) false;; 707 | *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; 708 | esac || 709 | as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; 710 | esac 711 | case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac 712 | as_fn_append ac_file_inputs " '$ac_f'" 713 | done 714 | 715 | # Let's still pretend it is `configure' which instantiates (i.e., don't 716 | # use $as_me), people would be surprised to read: 717 | # /* config.h. Generated by config.status. */ 718 | configure_input='Generated from '` 719 | $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' 720 | `' by configure.' 721 | if test x"$ac_file" != x-; then 722 | configure_input="$ac_file. $configure_input" 723 | { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 724 | $as_echo "$as_me: creating $ac_file" >&6;} 725 | fi 726 | # Neutralize special characters interpreted by sed in replacement strings. 727 | case $configure_input in #( 728 | *\&* | *\|* | *\\* ) 729 | ac_sed_conf_input=`$as_echo "$configure_input" | 730 | sed 's/[\\\\&|]/\\\\&/g'`;; #( 731 | *) ac_sed_conf_input=$configure_input;; 732 | esac 733 | 734 | case $ac_tag in 735 | *:-:* | *:-) cat >"$ac_tmp/stdin" \ 736 | || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; 737 | esac 738 | ;; 739 | esac 740 | 741 | ac_dir=`$as_dirname -- "$ac_file" || 742 | $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ 743 | X"$ac_file" : 'X\(//\)[^/]' \| \ 744 | X"$ac_file" : 'X\(//\)$' \| \ 745 | X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || 746 | $as_echo X"$ac_file" | 747 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ 748 | s//\1/ 749 | q 750 | } 751 | /^X\(\/\/\)[^/].*/{ 752 | s//\1/ 753 | q 754 | } 755 | /^X\(\/\/\)$/{ 756 | s//\1/ 757 | q 758 | } 759 | /^X\(\/\).*/{ 760 | s//\1/ 761 | q 762 | } 763 | s/.*/./; q'` 764 | as_dir="$ac_dir"; as_fn_mkdir_p 765 | ac_builddir=. 766 | 767 | case "$ac_dir" in 768 | .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; 769 | *) 770 | ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` 771 | # A ".." for each directory in $ac_dir_suffix. 772 | ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` 773 | case $ac_top_builddir_sub in 774 | "") ac_top_builddir_sub=. ac_top_build_prefix= ;; 775 | *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; 776 | esac ;; 777 | esac 778 | ac_abs_top_builddir=$ac_pwd 779 | ac_abs_builddir=$ac_pwd$ac_dir_suffix 780 | # for backward compatibility: 781 | ac_top_builddir=$ac_top_build_prefix 782 | 783 | case $srcdir in 784 | .) # We are building in place. 785 | ac_srcdir=. 786 | ac_top_srcdir=$ac_top_builddir_sub 787 | ac_abs_top_srcdir=$ac_pwd ;; 788 | [\\/]* | ?:[\\/]* ) # Absolute name. 789 | ac_srcdir=$srcdir$ac_dir_suffix; 790 | ac_top_srcdir=$srcdir 791 | ac_abs_top_srcdir=$srcdir ;; 792 | *) # Relative name. 793 | ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix 794 | ac_top_srcdir=$ac_top_build_prefix$srcdir 795 | ac_abs_top_srcdir=$ac_pwd/$srcdir ;; 796 | esac 797 | ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix 798 | 799 | 800 | case $ac_mode in 801 | :F) 802 | # 803 | # CONFIG_FILE 804 | # 805 | 806 | # If the template does not know about datarootdir, expand it. 807 | # FIXME: This hack should be removed a few years after 2.60. 808 | ac_datarootdir_hack=; ac_datarootdir_seen= 809 | ac_sed_dataroot=' 810 | /datarootdir/ { 811 | p 812 | q 813 | } 814 | /@datadir@/p 815 | /@docdir@/p 816 | /@infodir@/p 817 | /@localedir@/p 818 | /@mandir@/p' 819 | case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in 820 | *datarootdir*) ac_datarootdir_seen=yes;; 821 | *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) 822 | { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 823 | $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} 824 | ac_datarootdir_hack=' 825 | s&@datadir@&${datarootdir}&g 826 | s&@docdir@&${datarootdir}/doc/${PACKAGE_TARNAME}&g 827 | s&@infodir@&${datarootdir}/info&g 828 | s&@localedir@&${datarootdir}/locale&g 829 | s&@mandir@&${datarootdir}/man&g 830 | s&\${datarootdir}&${prefix}/share&g' ;; 831 | esac 832 | ac_sed_extra="/^[ ]*VPATH[ ]*=[ ]*/{ 833 | h 834 | s/// 835 | s/^/:/ 836 | s/[ ]*$/:/ 837 | s/:\$(srcdir):/:/g 838 | s/:\${srcdir}:/:/g 839 | s/:@srcdir@:/:/g 840 | s/^:*// 841 | s/:*$// 842 | x 843 | s/\(=[ ]*\).*/\1/ 844 | G 845 | s/\n// 846 | s/^[^=]*=[ ]*$// 847 | } 848 | 849 | :t 850 | /@[a-zA-Z_][a-zA-Z_0-9]*@/!b 851 | s|@configure_input@|$ac_sed_conf_input|;t t 852 | s&@top_builddir@&$ac_top_builddir_sub&;t t 853 | s&@top_build_prefix@&$ac_top_build_prefix&;t t 854 | s&@srcdir@&$ac_srcdir&;t t 855 | s&@abs_srcdir@&$ac_abs_srcdir&;t t 856 | s&@top_srcdir@&$ac_top_srcdir&;t t 857 | s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t 858 | s&@builddir@&$ac_builddir&;t t 859 | s&@abs_builddir@&$ac_abs_builddir&;t t 860 | s&@abs_top_builddir@&$ac_abs_top_builddir&;t t 861 | $ac_datarootdir_hack 862 | " 863 | eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ 864 | >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 865 | 866 | test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && 867 | { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && 868 | { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ 869 | "$ac_tmp/out"`; test -z "$ac_out"; } && 870 | { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' 871 | which seems to be undefined. Please make sure it is defined" >&5 872 | $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' 873 | which seems to be undefined. Please make sure it is defined" >&2;} 874 | 875 | rm -f "$ac_tmp/stdin" 876 | case $ac_file in 877 | -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; 878 | *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; 879 | esac \ 880 | || as_fn_error $? "could not create $ac_file" "$LINENO" 5 881 | ;; 882 | 883 | 884 | 885 | esac 886 | 887 | done # for ac_tag 888 | 889 | 890 | as_fn_exit 0 891 | --------------------------------------------------------------------------------