Skip to content

Commit c110830

Browse files
authored
Merge pull request #10 from khubo/between-circles
Add method to generate point between circles
2 parents 5eed0fa + 8bcdf8d commit c110830

File tree

7 files changed

+3375
-2673
lines changed

7 files changed

+3375
-2673
lines changed

.circleci/config.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,12 @@ jobs:
4141
name: prettier
4242
command: yarn prettier:ci
4343
- run:
44-
name: test & coveralls
45-
command: yarn test --coverageReporters=text-lcov | yarn coveralls
44+
name: jest
45+
command: yarn test
46+
- run:
47+
name: codecov
48+
command: yarn codecov
49+
4650
- persist_to_workspace:
4751
root: ~/repo
4852
paths:

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ We use it to stress test our [geohash](https://en.wikipedia.org/wiki/Geohash) ba
66
It works anywhere JavaScript runs.
77

88
[![Build](https://circleci.com/gh/rmrs/random-location.svg?style=svg)](https://circleci.com/gh/rmrs/random-location)
9-
[![Coverage](https://coveralls.io/repos/github/rmrs/random-location/badge.svg?branch=modernize_js_repo)](https://coveralls.io/github/rmrs/random-location?branch=modernize_js_repo)
9+
[![Coverage](https://codecov.io/gh/rmrs/random-location/branch/master/graph/badge.svg)](https://codecov.io/gh/rmrs/random-location)
1010
[![Version](https://img.shields.io/npm/v/random-location.svg?style=flat-square)](http://npm.im/random-location)
1111
[![MIT License](https://img.shields.io/npm/l/random-location.svg?style=flat-square)](http://opensource.org/licenses/MIT)
1212
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
@@ -74,6 +74,24 @@ Where:
7474
- **`radius`** *required* The distance (meters) from `centerPoint`.
7575
- **`randomFn`** *optional* A random function. Output is >=0 and <=1. Allows usage of seeded random number generators (see [`seedrandom`](https://www.npmjs.com/package/seedrandom)) - more predictability when testing.
7676

77+
### `randomLocation.randomAnnulusPoint(...)`
78+
79+
Outputs a Point ( `{ latitude: ..., longitude: ... }`) of random coordinates in a region bounded by two concentric circles (annulus).
80+
81+
Function definition:
82+
83+
```js
84+
const randomCircumferencePoint= (centerPoint, radius, randomFn = Math.random) => { ... }
85+
```
86+
87+
Where:
88+
89+
- **`centerPoint`** *required* An object with a `latitude` and `longitude` fields.
90+
- **`innerRadius`** *required* The readius of the smaller circle.
91+
- **`outerRadius`** *required* The readius of the larger circle.
92+
- **`randomFn`** *optional* A random function. Output is >=0 and <=1. Allows usage of seeded random number generators (see [`seedrandom`](https://www.npmjs.com/package/seedrandom)) - more predictability when testing.
93+
94+
7795

7896
## Usage
7997

index.d.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
1-
declare module "random-location" {
2-
interface Point {
3-
latitude: number,
4-
longitude: number
5-
}
1+
declare module 'random-location' {
2+
interface Point {
3+
latitude: number;
4+
longitude: number;
5+
}
66

7-
function randomCirclePoint(centerPoint: Point, radius: number, randomFn?: (...args: any[]) => number): Point;
8-
function randomCircumferencePoint(centerPoint: Point, radius: number, randomFn?: (...args: any[]) => number): Point;
7+
function randomCirclePoint (
8+
centerPoint: Point,
9+
radius: number,
10+
randomFn?: (...args: any[]) => number
11+
): Point;
12+
function randomCircumferencePoint (
13+
centerPoint: Point,
14+
radius: number,
15+
randomFn?: (...args: any[]) => number
16+
): Point;
17+
function randomAnnulusPoint (
18+
centerPoint: PointerEvent,
19+
innerRadius: number,
20+
outerRadius: number,
21+
randomFn?: (...args: any[]) => number
22+
): PointerEvent;
923
}

package.json

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,30 @@
1212
"build": "npm-run-all --parallel build:*",
1313
"build:babel": "babel --ignore '**/*.test.js' src -d dist --verbose",
1414
"build:webpack": "webpack --display-modules ./src -o dist/randomLocation.umd.js",
15-
"prettier:ci": "prettier --list-different \"src/**/*.js\"",
15+
"prettier:ci": "prettier --check \"src/**/*.js\"",
1616
"semantic-release": "yarn build && semantic-release"
1717
},
1818
"devDependencies": {
19-
"@babel/cli": "^7.6.2",
20-
"@babel/core": "^7.6.2",
21-
"@babel/preset-env": "^7.6.2",
22-
"@commitlint/cli": "^8.2.0",
23-
"@commitlint/config-conventional": "^8.2.0",
24-
"babel-eslint": "^10.0.3",
25-
"coveralls": "^3.0.6",
26-
"eslint": "^6.4.0",
27-
"eslint-config-prettier": "^6.3.0",
28-
"eslint-plugin-jest": "^22.17.0",
29-
"eslint-plugin-prettier": "^3.1.1",
30-
"husky": "^3.0.7",
31-
"jest": "^24.9.0",
19+
"@babel/cli": "^7.8.4",
20+
"@babel/core": "^7.9.0",
21+
"@babel/preset-env": "^7.9.5",
22+
"@commitlint/cli": "^8.3.5",
23+
"@commitlint/config-conventional": "^8.3.4",
24+
"babel-eslint": "^10.1.0",
25+
"codecov": "^3.6.5",
26+
"eslint": "^6.8.0",
27+
"eslint-config-prettier": "^6.11.0",
28+
"eslint-plugin-jest": "^23.8.2",
29+
"eslint-plugin-prettier": "^3.1.3",
30+
"husky": "^4.2.5",
31+
"jest": "^25.4.0",
3232
"npm-run-all": "4.1.5",
33-
"prettier": "^1.18.2",
34-
"rimraf": "3.0.0",
33+
"prettier": "^2.0.5",
34+
"rimraf": "3.0.2",
3535
"seedrandom": "^3.0.5",
36-
"semantic-release": "^15.13.24",
37-
"webpack": "4.41.0",
38-
"webpack-cli": "^3.3.9"
36+
"semantic-release": "^17.0.7",
37+
"webpack": "4.43.0",
38+
"webpack-cli": "^3.3.11"
3939
},
4040
"husky": {
4141
"hooks": {

src/index.js

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ const DEG_TO_RAD = Math.PI / 180.0;
33
const THREE_PI = Math.PI * 3;
44
const TWO_PI = Math.PI * 2;
55

6-
const toRadians = deg => deg * DEG_TO_RAD;
7-
const toDegrees = rad => rad / DEG_TO_RAD;
6+
const toRadians = (deg) => deg * DEG_TO_RAD;
7+
const toDegrees = (rad) => rad / DEG_TO_RAD;
88

99
/*
1010
Given a centerPoint C and a radius R, returns a random point that is on the
@@ -69,6 +69,38 @@ const randomCirclePoint = (centerPoint, radius, randomFn = Math.random) => {
6969
);
7070
};
7171

72+
/**
73+
* Returns a random point in a region bounded by two concentric circles (annulus).
74+
*
75+
* centerPoint - the center point of both circles.
76+
* innerRadius - the radius of the smaller circle.
77+
* outerRadius - the radius of the larger circle
78+
* randomFn - *optional* A random function. Output is >=0 and <=1. Allows
79+
* usage of seeded random number generators - i.e. allows us to predict
80+
* generated random coordiantes. default is Math.random()
81+
*
82+
*/
83+
const randomAnnulusPoint = (
84+
centerPoint,
85+
innerRadius,
86+
outerRadius,
87+
randomFn = Math.random
88+
) => {
89+
if (innerRadius >= outerRadius) {
90+
throw new Error(
91+
`innerRadius (${innerRadius}) should be smaller than outerRadius (${outerRadius})`
92+
);
93+
}
94+
95+
const deltaRadius = outerRadius - innerRadius;
96+
97+
return randomCircumferencePoint(
98+
centerPoint,
99+
innerRadius + Math.sqrt(randomFn()) * deltaRadius,
100+
randomFn
101+
);
102+
};
103+
72104
/*
73105
Returns the distance in meters between two points P1 and P2.
74106
@@ -109,4 +141,5 @@ module.exports = {
109141
haversine,
110142
randomCircumferencePoint,
111143
randomCirclePoint,
144+
randomAnnulusPoint,
112145
};

src/index.test.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,65 @@ describe('random-location', () => {
108108
}
109109
});
110110
});
111+
112+
describe('random generation of random annulus points', () => {
113+
test('innerRadius is larger than outerRadius', () => {
114+
// Eiffel Tower
115+
const P1 = {
116+
latitude: 48.8583736,
117+
longitude: 2.2922926,
118+
};
119+
const innerRadius = 1000; // meters
120+
const outerRadius = 123;
121+
expect(() =>
122+
randomLocation.randomAnnulusPoint(P1, innerRadius, outerRadius)
123+
).toThrow(
124+
`innerRadius (${innerRadius}) should be smaller than outerRadius (${outerRadius})`
125+
);
126+
});
127+
128+
test('on an annulus of two concentric circles', () => {
129+
// Eiffel Tower
130+
const P1 = {
131+
latitude: 48.8583736,
132+
longitude: 2.2922926,
133+
};
134+
const innerRadius = 1000; // meters
135+
const outerRadius = 2000;
136+
137+
for (let i = 0; i < 100; i++) {
138+
const randomPoint = randomLocation.randomAnnulusPoint(
139+
P1,
140+
innerRadius,
141+
outerRadius
142+
);
143+
const distance = Math.floor(randomLocation.distance(P1, randomPoint));
144+
expect(distance).toBeLessThanOrEqual(outerRadius);
145+
expect(distance).toBeGreaterThanOrEqual(innerRadius);
146+
}
147+
});
148+
test('on an annulus of two concentric circles; using seedrandom', () => {
149+
// Eiffel Tower
150+
const P1 = {
151+
latitude: 48.8583736,
152+
longitude: 2.2922926,
153+
};
154+
const innerRadius = 1000; // meters
155+
const outerRadius = 2000;
156+
const seed = 'this is another seed';
157+
const randomFn = seedrandom(seed);
158+
159+
for (let i = 0; i < 100; i++) {
160+
const randomPoint = randomLocation.randomAnnulusPoint(
161+
P1,
162+
innerRadius,
163+
outerRadius,
164+
randomFn
165+
);
166+
const distance = Math.floor(randomLocation.distance(P1, randomPoint));
167+
expect(distance).toBeLessThanOrEqual(outerRadius);
168+
expect(distance).toBeGreaterThanOrEqual(innerRadius);
169+
}
170+
});
171+
});
111172
});

0 commit comments

Comments
 (0)