Skip to content

Commit 2e6c8fb

Browse files
committed
Accelerated code for distance from points to segments
1 parent cb3df21 commit 2e6c8fb

6 files changed

Lines changed: 75 additions & 33 deletions

File tree

DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: spatstat.utils
2-
Version: 3.2-2.003
3-
Date: 2026-04-29
2+
Version: 3.2-2.004
3+
Date: 2026-05-02
44
Title: Utility Functions for 'spatstat'
55
Authors@R: c(person("Adrian", "Baddeley",
66
role = c("aut", "cre"),

NEWS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
CHANGES IN spatstat.utils VERSION 3.2-2.003
2+
CHANGES IN spatstat.utils VERSION 3.2-2.004
33

44
OVERVIEW
55

R/xysegment.R

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#
22
# xysegment.S
33
#
4-
# $Revision: 1.22 $ $Date: 2022/04/28 03:25:59 $
4+
# $Revision: 1.23 $ $Date: 2026/05/02 06:04:37 $
55
#
66
# Low level utilities for analytic geometry for line segments
77
#
@@ -25,8 +25,9 @@
2525
#
2626
# NNdist2segs
2727
# distance to nearest line segment, from each point in a list.
28-
29-
28+
#
29+
# Copyright (c) Adrian Baddeley and Rob Foxall 1997-2026
30+
# GNU Public Licence (>= 2.0)
3031

3132
distpl <- function(p, l) {
3233
xp <- p[1]

inst/doc/packagesizes.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ date version nhelpfiles nobjects ndatasets Rlines srclines
3333
"2025-09-20" "3.2-0" 42 195 0 3716 2462
3434
"2026-01-08" "3.2-1" 43 196 0 3754 2535
3535
"2026-03-10" "3.2-2" 44 197 0 3778 2535
36-
"2026-04-29" "3.2-2.003" 44 197 0 3784 2542
36+
"2026-05-02" "3.2-2.004" 44 197 0 3785 2583

inst/info/packagesizes.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ date version nhelpfiles nobjects ndatasets Rlines srclines
3333
"2025-09-20" "3.2-0" 42 195 0 3716 2462
3434
"2026-01-08" "3.2-1" 43 196 0 3754 2535
3535
"2026-03-10" "3.2-2" 44 197 0 3778 2535
36-
"2026-04-29" "3.2-2.003" 44 197 0 3784 2542
36+
"2026-05-02" "3.2-2.004" 44 197 0 3785 2583

src/distseg.h

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@
1313
1414
Author: Adrian Baddeley 2018-2021
1515
16-
Copyright (C) Adrian Baddeley, Ege Rubak and Rolf Turner 2001-2021
16+
Copyright (C) Adrian Baddeley, Ege Rubak and Rolf Turner 2001-2026
1717
Licence: GNU Public Licence >= 2
1818
19-
$Revision: 1.3 $ $Date: 2022/10/19 02:58:46 $
19+
$Revision: 1.5 $ $Date: 2026/05/02 07:03:14 $
2020
2121
*/
2222

2323
void
2424
FNAME(
2525
/* input */
2626
double *xp,
27-
double *yp, /* point/pixel coordinates */
27+
double *yp, /* point (or pixel) coordinates */
2828
int *npoints,
2929
double *x0,
3030
double *y0,
@@ -33,7 +33,7 @@ FNAME(
3333
int *nsegments,
3434
double *epsilon, /* tolerance for short segments */
3535
/* output */
36-
double *dist2 /* squared distance from pixel
36+
double *dist2 /* squared distance from point
3737
to nearest line segment
3838
INITIALISED TO LARGE VALUE */
3939
#ifdef WANT_INDEX
@@ -42,9 +42,15 @@ FNAME(
4242
) {
4343
int i,j, np, nseg, maxchunk;
4444
double dx,dy,leng,co,si; /* parameters of segment */
45+
double xpi, ypi, x0j, y0j, x1j, y1j; /* coordinates */
4546
double xdif0,ydif0,xdif1,ydif1,xpr,ypr; /* vectors */
4647
double dsq0,dsq1,dsq,dsqperp; /* squared distances */
4748
double eps;
49+
double *xpp, *ypp; /* pointers into data xp[], yp[] */
50+
double *dist2p; /* pointer into dist2[] */
51+
#ifdef WANT_INDEX
52+
int *indexp; /* pointer into index[] */
53+
#endif
4854

4955
np = *npoints;
5056
nseg = *nsegments;
@@ -53,55 +59,90 @@ FNAME(
5359
OUTERCHUNKLOOP(j, nseg, maxchunk, 16384) {
5460
R_CheckUserInterrupt();
5561
INNERCHUNKLOOP(j, nseg, maxchunk, 16384) {
56-
dx = x1[j] - x0[j];
57-
dy = y1[j] - y0[j];
62+
/* segment j coordinates */
63+
x0j = x0[j];
64+
y0j = y0[j];
65+
x1j = x1[j];
66+
y1j = y1[j];
67+
/* segment j geometry */
68+
dx = x1j - x0j;
69+
dy = y1j - y0j;
5870
leng = hypot(dx, dy);
71+
/* loop over points */
5972
if(leng > eps) {
6073
/* normal case */
6174
co = dx/leng;
6275
si = dy/leng;
63-
for(i = 0; i < np; i++) {
64-
/* vectors from pixel to segment endpoints */
65-
xdif0 = xp[i] - x0[j];
66-
ydif0 = yp[i] - y0[j];
67-
xdif1 = xp[i] - x1[j];
68-
ydif1 = yp[i] - y1[j];
76+
for(
77+
#ifdef WANT_INDEX
78+
i = np, xpp = xp, ypp = yp, dist2p = dist2, indexp = index;
79+
i > 0;
80+
i--, xpp++, ypp++, dist2p++, indexp++
81+
#else
82+
i = np, xpp = xp, ypp = yp, dist2p = dist2;
83+
i > 0;
84+
i--, xpp++, ypp++, dist2p++
85+
#endif
86+
) {
87+
/* point i coordinates */
88+
xpi = *xpp;
89+
ypi = *ypp;
90+
/* vectors from point i to endpoints of segment j */
91+
xdif0 = xpi - x0j;
92+
ydif0 = ypi - y0j;
93+
xdif1 = xpi - x1j;
94+
ydif1 = ypi - y1j;
6995
/* squared distances to segment endpoints */
7096
dsq0 = xdif0 * xdif0 + ydif0 * ydif0;
7197
dsq1 = xdif1 * xdif1 + ydif1 * ydif1;
7298
dsq = (dsq0 < dsq1) ? dsq0 : dsq1;
7399
/* rotate pixel around 1st endpoint of segment
74100
so that line segment lies in x axis */
75101
xpr = xdif0 * co + ydif0 * si;
76-
ypr = -xdif0 * si + ydif0 * co;
77102
/* perpendicular distance applies only in perpendicular region */
78103
if(xpr >= 0.0 && xpr <= leng) {
104+
ypr = -xdif0 * si + ydif0 * co;
79105
dsqperp = ypr * ypr;
80106
if(dsqperp < dsq) dsq = dsqperp;
81107
}
82-
if(dist2[i] > dsq) {
83-
dist2[i] = dsq;
108+
/* update minimum distance for pixel i */
109+
if(*dist2p > dsq) {
110+
*dist2p = dsq;
84111
#ifdef WANT_INDEX
85-
index[i] = j;
112+
*indexp = j;
86113
#endif
87114
}
88115
}
89116
} else {
90117
/* short segment - use endpoints only */
91-
for(i = 0; i < np; i++) {
92-
/* vectors from pixel to segment endpoints */
93-
xdif0 = xp[i] - x0[j];
94-
ydif0 = yp[i] - y0[j];
95-
xdif1 = xp[i] - x1[j];
96-
ydif1 = yp[i] - y1[j];
118+
for(
119+
#ifdef WANT_INDEX
120+
i = np, xpp = xp, ypp = yp, dist2p = dist2, indexp = index;
121+
i > 0;
122+
i--, xpp++, ypp++, dist2p++, indexp++
123+
#else
124+
i = np, xpp = xp, ypp = yp, dist2p = dist2;
125+
i > 0;
126+
i--, xpp++, ypp++, dist2p++
127+
#endif
128+
) {
129+
/* point i coordinates */
130+
xpi = *xpp;
131+
ypi = *ypp;
132+
/* vectors from point i to endpoints of segment j */
133+
xdif0 = xpi - x0j;
134+
ydif0 = ypi - y0j;
135+
xdif1 = xpi - x1j;
136+
ydif1 = ypi - y1j;
97137
/* squared distances to segment endpoints */
98138
dsq0 = xdif0 * xdif0 + ydif0 * ydif0;
99139
dsq1 = xdif1 * xdif1 + ydif1 * ydif1;
100140
dsq = (dsq0 < dsq1) ? dsq0 : dsq1;
101-
if(dist2[i] > dsq) {
102-
dist2[i] = dsq;
141+
/* update minimum distance for pixel i */
142+
if(*dist2p > dsq) {
143+
*dist2p = dsq;
103144
#ifdef WANT_INDEX
104-
index[i] = j;
145+
*indexp = j;
105146
#endif
106147
}
107148
}

0 commit comments

Comments
 (0)