mrpas 2.1.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -16
- package/dist/cjs/index.js +51 -17
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +51 -17
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Just use npm:
|
|
|
8
8
|
npm install mrpas
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Or grab the code from the [repository](https://
|
|
11
|
+
Or grab the code from the [repository](https://github.com/mingos777/mrpas) and include it in your project.
|
|
12
12
|
|
|
13
13
|
## Usage
|
|
14
14
|
|
|
@@ -28,9 +28,29 @@ ES modules can import the same named export:
|
|
|
28
28
|
import { Mrpas } from "mrpas";
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
Alternatively, instead of the callback, you can pass the map's transparency data as a flat array of `width * height` values, in row-major order (the cell at `x, y` is at index `y * width + x`). Truthy values denote transparent cells, falsy ones denote obstacles:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
const transparency = new Uint8Array(20 * 20); // fill with 1 for transparent cells, 0 for obstacles
|
|
35
|
+
|
|
36
|
+
const fov = new Mrpas(20, 20, transparency);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Any array-like object will do: a typed array, an array of booleans, numbers, etc. `Mrpas` keeps a reference to the array rather than a copy, so changes to the map (e.g. a door opening) only require updating the array's values. Cells outside the map are treated as obstacles.
|
|
40
|
+
|
|
41
|
+
Using transparency data is usually faster than using a callback.
|
|
42
|
+
|
|
31
43
|
### Compute FOV
|
|
32
44
|
|
|
33
|
-
Compute the field of view for any set of coordinates by calling the `Mrpas#compute()` method and passing it the origin coordinates, FOV calculation radius and
|
|
45
|
+
Compute the field of view for any set of coordinates by calling the `Mrpas#compute()` method and passing it the origin coordinates, the FOV calculation radius and a callback for marking a cell as visible:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
fov.compute(10, 10, 7, (x, y) => map[x][y].visible = true);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The callback is called once for every cell in the field of view. Cells that aren't visible are never reported, so remember to clear your map's visibility before computing the FOV again.
|
|
52
|
+
|
|
53
|
+
Alternatively, you can pass two callbacks: one for determining whether a cell has been marked as visible, and the other for marking it as visible:
|
|
34
54
|
|
|
35
55
|
```
|
|
36
56
|
fov.compute(
|
|
@@ -42,7 +62,9 @@ fov.compute(
|
|
|
42
62
|
);
|
|
43
63
|
```
|
|
44
64
|
|
|
45
|
-
|
|
65
|
+
In this case, the visibility check callback must only report the cells marked as visible during the current computation: the visibility has to be cleared before each call. Otherwise, cells left visible by a previous computation can affect the result. Calling `compute()` with a single callback tracks visibility internally, which avoids this problem and is usually faster.
|
|
66
|
+
|
|
67
|
+
To calculate the FOV on the entire map, regardless of radius, you may pass `Infinity` as the radius value. Just remember that a transparency callback (the one passed to the constructor) will need to account for this, returning `false` when a cell outside the map is checked. Transparency data handles this automatically.
|
|
46
68
|
|
|
47
69
|
### Map dimension changing
|
|
48
70
|
|
|
@@ -52,37 +74,38 @@ Should your map change dimensions, you can inform `Mrpas` about it by calling `M
|
|
|
52
74
|
fov.setMapDimensions(40, 40);
|
|
53
75
|
```
|
|
54
76
|
|
|
77
|
+
If you're using transparency data, the array's size and layout depend on the map dimensions, so create a new `Mrpas` instance with the new array instead.
|
|
78
|
+
|
|
55
79
|
### TypeScript
|
|
56
80
|
|
|
57
81
|
MRPAS includes a TypeScript declaration file. It can be used in TypeScript projects without additional typings:
|
|
58
82
|
|
|
59
83
|
```
|
|
60
|
-
import { Mrpas } from "mrpas";
|
|
84
|
+
import { Mrpas, TransparencyData } from "mrpas";
|
|
61
85
|
|
|
62
|
-
const
|
|
86
|
+
const transparency: TransparencyData = new Uint8Array(20 * 20);
|
|
87
|
+
const fov: Mrpas = new Mrpas(20, 20, transparency);
|
|
63
88
|
|
|
64
|
-
fov.compute(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
7,
|
|
68
|
-
(x: number, y: number): boolean => map[x][y].visible,
|
|
69
|
-
(x: number, y: number): void => map[x][y].visible = true
|
|
70
|
-
);
|
|
89
|
+
fov.compute(10, 10, 7, (x: number, y: number): void => {
|
|
90
|
+
map[x][y].visible = true;
|
|
91
|
+
});
|
|
71
92
|
```
|
|
72
93
|
|
|
94
|
+
The callback types, `IsTransparentFunc`, `IsVisibleFunc` and `SetVisibleFunc`, are exported as well.
|
|
95
|
+
|
|
73
96
|
## About MRPAS
|
|
74
97
|
|
|
75
98
|
MRPAS, or [Mingos' Restrictive Precise Angle Shadowcasting](http://www.roguebasin.com/index.php?title=Restrictive_Precise_Angle_Shadowcasting) (Precise Angle Shadowcasting for short) is a field of view (FOV) computation algorithm. Given a 2D grid with a source point *S* and *n* points marked as obstacles, it will determine all points visible from *S*.
|
|
76
99
|
|
|
77
100
|
To visualise this, let the following be a 2D grid of 20 by 20 points. The character `@` represents the field of view source, `#` characters represent obstacles. Cells with yellow background are in the source point's field of view:
|
|
78
101
|
|
|
79
|
-

|
|
80
103
|
|
|
81
104
|
### Real life uses
|
|
82
105
|
|
|
83
106
|
This algorithm was conceived in the year 2008 for the purpose of being used in a [roguelike](http://www.roguebasin.com/index.php?title=What_a_roguelike_is) game. To this day, roguelikes remain the focus of MRPAS.
|
|
84
107
|
|
|
85
|
-
The algorithm was originally written in C and was included in the roguelike library [libtcod](https://
|
|
108
|
+
The algorithm was originally written in C and was included in the roguelike library [libtcod](https://github.com/libtcod/libtcod). It also contained a C++ wrapper.
|
|
86
109
|
|
|
87
110
|
Since 2008, MRPAS has been implemented [in various languages](http://www.roguebasin.com/index.php?title=Restrictive_Precise_Angle_Shadowcasting#Implementations), and has been successfully used in numerous roguelike games.
|
|
88
111
|
|
|
@@ -106,7 +129,7 @@ Considering the mathematics behind determining the FOV, the line of sight from A
|
|
|
106
129
|
|
|
107
130
|
The algorithm's asymmetry can be seen on the following image, where the `.` character has been used to mark asymmetric points (if on yellow background, they can be seen from the source, but cannot see the source; if on black, the source is visible from them, but it cannot see them):
|
|
108
131
|
|
|
109
|
-

|
|
110
133
|
|
|
111
134
|
On the above map, 1.6% of all points not containing an obstacle are asymmetric.
|
|
112
135
|
|
|
@@ -114,7 +137,7 @@ The percentage of asymmetric points is within the range of single digit numbers,
|
|
|
114
137
|
|
|
115
138
|
For comparison, here's an "outdoor" map with 3.9% asymmetric points:
|
|
116
139
|
|
|
117
|
-

|
|
118
141
|
|
|
119
142
|
### Performance
|
|
120
143
|
|
package/dist/cjs/index.js
CHANGED
|
@@ -5,14 +5,17 @@ class Mrpas {
|
|
|
5
5
|
mapWidth;
|
|
6
6
|
mapHeight;
|
|
7
7
|
isTransparent;
|
|
8
|
-
constructor(mapWidth, mapHeight,
|
|
8
|
+
constructor(mapWidth, mapHeight, transparency) {
|
|
9
9
|
this.mapWidth = mapWidth;
|
|
10
10
|
this.mapHeight = mapHeight;
|
|
11
|
-
this.isTransparent =
|
|
11
|
+
this.isTransparent = typeof transparency === "function"
|
|
12
|
+
? transparency
|
|
13
|
+
: (x, y) => x >= 0 && x < this.mapWidth && y >= 0 && y < this.mapHeight &&
|
|
14
|
+
!!transparency[y * this.mapWidth + x];
|
|
12
15
|
}
|
|
13
16
|
computeOctantY(deltaX, deltaY, data) {
|
|
14
|
-
const startSlopes =
|
|
15
|
-
const endSlopes =
|
|
17
|
+
const startSlopes = data.startSlopes;
|
|
18
|
+
const endSlopes = data.endSlopes;
|
|
16
19
|
const minX = data.minX;
|
|
17
20
|
const maxX = data.maxX;
|
|
18
21
|
const minY = data.minY;
|
|
@@ -22,6 +25,8 @@ class Mrpas {
|
|
|
22
25
|
const isTransparent = this.isTransparent;
|
|
23
26
|
const isVisible = data.isVisible;
|
|
24
27
|
const setVisible = data.setVisible;
|
|
28
|
+
const visibility = data.visibility;
|
|
29
|
+
const width = maxX - minX + 1;
|
|
25
30
|
let iteration = 1;
|
|
26
31
|
let totalObstacles = 0;
|
|
27
32
|
let obstaclesInLastLine = 0;
|
|
@@ -53,11 +58,14 @@ class Mrpas {
|
|
|
53
58
|
transparencyChecked = false;
|
|
54
59
|
if (obstaclesInLastLine > 0) {
|
|
55
60
|
diagonalOpen = behindOpen;
|
|
56
|
-
behindOpen = isVisible(x, y - deltaY)
|
|
61
|
+
behindOpen = (visibility === null ? isVisible(x, y - deltaY) : visibility[(y - deltaY - minY) * width + x - minX] === 1) &&
|
|
62
|
+
isTransparent(x, y - deltaY);
|
|
57
63
|
if (!behindOpen &&
|
|
58
64
|
!(processedCell > firstCell
|
|
59
65
|
? diagonalOpen
|
|
60
|
-
: isVisible(x - deltaX, y - deltaY)
|
|
66
|
+
: (visibility === null ? isVisible(x - deltaX, y - deltaY) : x - deltaX >= minX && x - deltaX <= maxX &&
|
|
67
|
+
visibility[(y - deltaY - minY) * width + x - deltaX - minX] === 1) &&
|
|
68
|
+
isTransparent(x - deltaX, y - deltaY))) {
|
|
61
69
|
visible = false;
|
|
62
70
|
}
|
|
63
71
|
else {
|
|
@@ -94,6 +102,9 @@ class Mrpas {
|
|
|
94
102
|
}
|
|
95
103
|
if (visible) {
|
|
96
104
|
setVisible(x, y);
|
|
105
|
+
if (visibility !== null) {
|
|
106
|
+
visibility[(y - minY) * width + x - minX] = 1;
|
|
107
|
+
}
|
|
97
108
|
if (!transparencyChecked) {
|
|
98
109
|
cellTransparent = isTransparent(x, y);
|
|
99
110
|
}
|
|
@@ -114,8 +125,8 @@ class Mrpas {
|
|
|
114
125
|
}
|
|
115
126
|
}
|
|
116
127
|
computeOctantX(deltaX, deltaY, data) {
|
|
117
|
-
const startSlopes =
|
|
118
|
-
const endSlopes =
|
|
128
|
+
const startSlopes = data.startSlopes;
|
|
129
|
+
const endSlopes = data.endSlopes;
|
|
119
130
|
const minX = data.minX;
|
|
120
131
|
const maxX = data.maxX;
|
|
121
132
|
const minY = data.minY;
|
|
@@ -125,6 +136,8 @@ class Mrpas {
|
|
|
125
136
|
const isTransparent = this.isTransparent;
|
|
126
137
|
const isVisible = data.isVisible;
|
|
127
138
|
const setVisible = data.setVisible;
|
|
139
|
+
const visibility = data.visibility;
|
|
140
|
+
const width = maxX - minX + 1;
|
|
128
141
|
let iteration = 1;
|
|
129
142
|
let totalObstacles = 0;
|
|
130
143
|
let obstaclesInLastLine = 0;
|
|
@@ -156,11 +169,14 @@ class Mrpas {
|
|
|
156
169
|
transparencyChecked = false;
|
|
157
170
|
if (obstaclesInLastLine > 0) {
|
|
158
171
|
diagonalOpen = behindOpen;
|
|
159
|
-
behindOpen = isVisible(x - deltaX, y)
|
|
172
|
+
behindOpen = (visibility === null ? isVisible(x - deltaX, y) : visibility[(y - minY) * width + x - deltaX - minX] === 1) &&
|
|
173
|
+
isTransparent(x - deltaX, y);
|
|
160
174
|
if (!behindOpen &&
|
|
161
175
|
!(processedCell > firstCell
|
|
162
176
|
? diagonalOpen
|
|
163
|
-
: isVisible(x - deltaX, y - deltaY)
|
|
177
|
+
: (visibility === null ? isVisible(x - deltaX, y - deltaY) : y - deltaY >= minY && y - deltaY <= maxY &&
|
|
178
|
+
visibility[(y - deltaY - minY) * width + x - deltaX - minX] === 1) &&
|
|
179
|
+
isTransparent(x - deltaX, y - deltaY))) {
|
|
164
180
|
visible = false;
|
|
165
181
|
}
|
|
166
182
|
else {
|
|
@@ -197,6 +213,9 @@ class Mrpas {
|
|
|
197
213
|
}
|
|
198
214
|
if (visible) {
|
|
199
215
|
setVisible(x, y);
|
|
216
|
+
if (visibility !== null) {
|
|
217
|
+
visibility[(y - minY) * width + x - minX] = 1;
|
|
218
|
+
}
|
|
200
219
|
if (!transparencyChecked) {
|
|
201
220
|
cellTransparent = isTransparent(x, y);
|
|
202
221
|
}
|
|
@@ -220,17 +239,32 @@ class Mrpas {
|
|
|
220
239
|
this.mapWidth = mapWidth;
|
|
221
240
|
this.mapHeight = mapHeight;
|
|
222
241
|
}
|
|
223
|
-
compute(originX, originY, radius,
|
|
242
|
+
compute(originX, originY, radius, isVisibleOrSetVisible, setVisibleFunc) {
|
|
243
|
+
const minX = Math.max(0, originX - radius);
|
|
244
|
+
const minY = Math.max(0, originY - radius);
|
|
245
|
+
const maxX = Math.min(this.mapWidth - 1, originX + radius);
|
|
246
|
+
const maxY = Math.min(this.mapHeight - 1, originY + radius);
|
|
247
|
+
const width = maxX - minX + 1;
|
|
248
|
+
const visibility = setVisibleFunc === undefined
|
|
249
|
+
? new Uint8Array(width * (maxY - minY + 1))
|
|
250
|
+
: null;
|
|
251
|
+
const setVisible = setVisibleFunc ?? isVisibleOrSetVisible;
|
|
252
|
+
if (visibility !== null) {
|
|
253
|
+
visibility[(originY - minY) * width + originX - minX] = 1;
|
|
254
|
+
}
|
|
224
255
|
setVisible(originX, originY);
|
|
225
256
|
const data = {
|
|
226
|
-
minX:
|
|
227
|
-
minY:
|
|
228
|
-
maxX:
|
|
229
|
-
maxY:
|
|
257
|
+
minX: minX,
|
|
258
|
+
minY: minY,
|
|
259
|
+
maxX: maxX,
|
|
260
|
+
maxY: maxY,
|
|
230
261
|
originX: originX,
|
|
231
262
|
originY: originY,
|
|
232
|
-
isVisible:
|
|
233
|
-
setVisible: setVisible
|
|
263
|
+
isVisible: isVisibleOrSetVisible,
|
|
264
|
+
setVisible: setVisible,
|
|
265
|
+
visibility: visibility,
|
|
266
|
+
startSlopes: [],
|
|
267
|
+
endSlopes: []
|
|
234
268
|
};
|
|
235
269
|
this.computeOctantY(1, 1, data);
|
|
236
270
|
this.computeOctantX(1, 1, data);
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
export type IsTransparentFunc = (x: number, y: number) => boolean;
|
|
2
2
|
export type IsVisibleFunc = (x: number, y: number) => boolean;
|
|
3
3
|
export type SetVisibleFunc = (x: number, y: number) => void;
|
|
4
|
+
export type TransparencyData = ArrayLike<unknown>;
|
|
4
5
|
export declare class Mrpas {
|
|
5
6
|
private mapWidth;
|
|
6
7
|
private mapHeight;
|
|
7
8
|
private readonly isTransparent;
|
|
8
|
-
constructor(mapWidth: number, mapHeight: number,
|
|
9
|
+
constructor(mapWidth: number, mapHeight: number, transparency: IsTransparentFunc | TransparencyData);
|
|
9
10
|
private computeOctantY;
|
|
10
11
|
private computeOctantX;
|
|
11
12
|
setMapDimensions(mapWidth: number, mapHeight: number): void;
|
|
13
|
+
compute(originX: number, originY: number, radius: number, setVisible: SetVisibleFunc): void;
|
|
12
14
|
compute(originX: number, originY: number, radius: number, isVisible: IsVisibleFunc, setVisible: SetVisibleFunc): void;
|
|
13
15
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -2,14 +2,17 @@ export class Mrpas {
|
|
|
2
2
|
mapWidth;
|
|
3
3
|
mapHeight;
|
|
4
4
|
isTransparent;
|
|
5
|
-
constructor(mapWidth, mapHeight,
|
|
5
|
+
constructor(mapWidth, mapHeight, transparency) {
|
|
6
6
|
this.mapWidth = mapWidth;
|
|
7
7
|
this.mapHeight = mapHeight;
|
|
8
|
-
this.isTransparent =
|
|
8
|
+
this.isTransparent = typeof transparency === "function"
|
|
9
|
+
? transparency
|
|
10
|
+
: (x, y) => x >= 0 && x < this.mapWidth && y >= 0 && y < this.mapHeight &&
|
|
11
|
+
!!transparency[y * this.mapWidth + x];
|
|
9
12
|
}
|
|
10
13
|
computeOctantY(deltaX, deltaY, data) {
|
|
11
|
-
const startSlopes =
|
|
12
|
-
const endSlopes =
|
|
14
|
+
const startSlopes = data.startSlopes;
|
|
15
|
+
const endSlopes = data.endSlopes;
|
|
13
16
|
const minX = data.minX;
|
|
14
17
|
const maxX = data.maxX;
|
|
15
18
|
const minY = data.minY;
|
|
@@ -19,6 +22,8 @@ export class Mrpas {
|
|
|
19
22
|
const isTransparent = this.isTransparent;
|
|
20
23
|
const isVisible = data.isVisible;
|
|
21
24
|
const setVisible = data.setVisible;
|
|
25
|
+
const visibility = data.visibility;
|
|
26
|
+
const width = maxX - minX + 1;
|
|
22
27
|
let iteration = 1;
|
|
23
28
|
let totalObstacles = 0;
|
|
24
29
|
let obstaclesInLastLine = 0;
|
|
@@ -50,11 +55,14 @@ export class Mrpas {
|
|
|
50
55
|
transparencyChecked = false;
|
|
51
56
|
if (obstaclesInLastLine > 0) {
|
|
52
57
|
diagonalOpen = behindOpen;
|
|
53
|
-
behindOpen = isVisible(x, y - deltaY)
|
|
58
|
+
behindOpen = (visibility === null ? isVisible(x, y - deltaY) : visibility[(y - deltaY - minY) * width + x - minX] === 1) &&
|
|
59
|
+
isTransparent(x, y - deltaY);
|
|
54
60
|
if (!behindOpen &&
|
|
55
61
|
!(processedCell > firstCell
|
|
56
62
|
? diagonalOpen
|
|
57
|
-
: isVisible(x - deltaX, y - deltaY)
|
|
63
|
+
: (visibility === null ? isVisible(x - deltaX, y - deltaY) : x - deltaX >= minX && x - deltaX <= maxX &&
|
|
64
|
+
visibility[(y - deltaY - minY) * width + x - deltaX - minX] === 1) &&
|
|
65
|
+
isTransparent(x - deltaX, y - deltaY))) {
|
|
58
66
|
visible = false;
|
|
59
67
|
}
|
|
60
68
|
else {
|
|
@@ -91,6 +99,9 @@ export class Mrpas {
|
|
|
91
99
|
}
|
|
92
100
|
if (visible) {
|
|
93
101
|
setVisible(x, y);
|
|
102
|
+
if (visibility !== null) {
|
|
103
|
+
visibility[(y - minY) * width + x - minX] = 1;
|
|
104
|
+
}
|
|
94
105
|
if (!transparencyChecked) {
|
|
95
106
|
cellTransparent = isTransparent(x, y);
|
|
96
107
|
}
|
|
@@ -111,8 +122,8 @@ export class Mrpas {
|
|
|
111
122
|
}
|
|
112
123
|
}
|
|
113
124
|
computeOctantX(deltaX, deltaY, data) {
|
|
114
|
-
const startSlopes =
|
|
115
|
-
const endSlopes =
|
|
125
|
+
const startSlopes = data.startSlopes;
|
|
126
|
+
const endSlopes = data.endSlopes;
|
|
116
127
|
const minX = data.minX;
|
|
117
128
|
const maxX = data.maxX;
|
|
118
129
|
const minY = data.minY;
|
|
@@ -122,6 +133,8 @@ export class Mrpas {
|
|
|
122
133
|
const isTransparent = this.isTransparent;
|
|
123
134
|
const isVisible = data.isVisible;
|
|
124
135
|
const setVisible = data.setVisible;
|
|
136
|
+
const visibility = data.visibility;
|
|
137
|
+
const width = maxX - minX + 1;
|
|
125
138
|
let iteration = 1;
|
|
126
139
|
let totalObstacles = 0;
|
|
127
140
|
let obstaclesInLastLine = 0;
|
|
@@ -153,11 +166,14 @@ export class Mrpas {
|
|
|
153
166
|
transparencyChecked = false;
|
|
154
167
|
if (obstaclesInLastLine > 0) {
|
|
155
168
|
diagonalOpen = behindOpen;
|
|
156
|
-
behindOpen = isVisible(x - deltaX, y)
|
|
169
|
+
behindOpen = (visibility === null ? isVisible(x - deltaX, y) : visibility[(y - minY) * width + x - deltaX - minX] === 1) &&
|
|
170
|
+
isTransparent(x - deltaX, y);
|
|
157
171
|
if (!behindOpen &&
|
|
158
172
|
!(processedCell > firstCell
|
|
159
173
|
? diagonalOpen
|
|
160
|
-
: isVisible(x - deltaX, y - deltaY)
|
|
174
|
+
: (visibility === null ? isVisible(x - deltaX, y - deltaY) : y - deltaY >= minY && y - deltaY <= maxY &&
|
|
175
|
+
visibility[(y - deltaY - minY) * width + x - deltaX - minX] === 1) &&
|
|
176
|
+
isTransparent(x - deltaX, y - deltaY))) {
|
|
161
177
|
visible = false;
|
|
162
178
|
}
|
|
163
179
|
else {
|
|
@@ -194,6 +210,9 @@ export class Mrpas {
|
|
|
194
210
|
}
|
|
195
211
|
if (visible) {
|
|
196
212
|
setVisible(x, y);
|
|
213
|
+
if (visibility !== null) {
|
|
214
|
+
visibility[(y - minY) * width + x - minX] = 1;
|
|
215
|
+
}
|
|
197
216
|
if (!transparencyChecked) {
|
|
198
217
|
cellTransparent = isTransparent(x, y);
|
|
199
218
|
}
|
|
@@ -217,17 +236,32 @@ export class Mrpas {
|
|
|
217
236
|
this.mapWidth = mapWidth;
|
|
218
237
|
this.mapHeight = mapHeight;
|
|
219
238
|
}
|
|
220
|
-
compute(originX, originY, radius,
|
|
239
|
+
compute(originX, originY, radius, isVisibleOrSetVisible, setVisibleFunc) {
|
|
240
|
+
const minX = Math.max(0, originX - radius);
|
|
241
|
+
const minY = Math.max(0, originY - radius);
|
|
242
|
+
const maxX = Math.min(this.mapWidth - 1, originX + radius);
|
|
243
|
+
const maxY = Math.min(this.mapHeight - 1, originY + radius);
|
|
244
|
+
const width = maxX - minX + 1;
|
|
245
|
+
const visibility = setVisibleFunc === undefined
|
|
246
|
+
? new Uint8Array(width * (maxY - minY + 1))
|
|
247
|
+
: null;
|
|
248
|
+
const setVisible = setVisibleFunc ?? isVisibleOrSetVisible;
|
|
249
|
+
if (visibility !== null) {
|
|
250
|
+
visibility[(originY - minY) * width + originX - minX] = 1;
|
|
251
|
+
}
|
|
221
252
|
setVisible(originX, originY);
|
|
222
253
|
const data = {
|
|
223
|
-
minX:
|
|
224
|
-
minY:
|
|
225
|
-
maxX:
|
|
226
|
-
maxY:
|
|
254
|
+
minX: minX,
|
|
255
|
+
minY: minY,
|
|
256
|
+
maxX: maxX,
|
|
257
|
+
maxY: maxY,
|
|
227
258
|
originX: originX,
|
|
228
259
|
originY: originY,
|
|
229
|
-
isVisible:
|
|
230
|
-
setVisible: setVisible
|
|
260
|
+
isVisible: isVisibleOrSetVisible,
|
|
261
|
+
setVisible: setVisible,
|
|
262
|
+
visibility: visibility,
|
|
263
|
+
startSlopes: [],
|
|
264
|
+
endSlopes: []
|
|
231
265
|
};
|
|
232
266
|
this.computeOctantY(1, 1, data);
|
|
233
267
|
this.computeOctantX(1, 1, data);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mrpas",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "A Field of View (FOV) computation algorithm.",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"build": "npm run build:esm && npm run build:cjs",
|
|
20
20
|
"build:esm": "tsc -p tsconfig.esm.json",
|
|
21
21
|
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
22
|
-
"watch": "tsc --watch -p tsconfig.esm.json"
|
|
22
|
+
"watch": "tsc --watch -p tsconfig.esm.json",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
23
24
|
},
|
|
24
25
|
"repository": {
|
|
25
26
|
"type": "git",
|