@@ -83,7 +83,7 @@ private void runBenchmarks() throws IOException {
8383 benchmarkCramping (world , itemCount , false );
8484 benchmarkCramping (world , itemCount , true );
8585 }
86- for (String distribution : List .of ("uniform" , "hotspot" , "no-hit" )) {
86+ for (String distribution : List .of ("uniform" , "hotspot" , "no-hit" , "enclosed-no-hit" )) {
8787 for (int itemCount : List .of (500 , 2000 , 8000 )) {
8888 for (int viewerCount : List .of (1 , 8 , 32 , 64 , 96 , 128 , 192 , 256 , 384 , 512 , 768 , 1024 )) {
8989 for (int seed = 0 ; seed < VISIBILITY_SEEDS ; seed ++) {
@@ -193,6 +193,10 @@ private void benchmarkVisibility(int itemCount, int viewerCount, String distribu
193193 items = randomPoints (random , itemCount , 0.0D , 256.0D );
194194 viewers = randomPoints (random , viewerCount , 768.0D , 256.0D );
195195 }
196+ case "enclosed-no-hit" -> {
197+ items = randomPoints (random , itemCount , 448.0D , 128.0D );
198+ viewers = enclosingRingPoints (random , viewerCount );
199+ }
196200 default -> throw new IllegalArgumentException ("Unknown visibility distribution: " + distribution );
197201 }
198202 LongSupplier linearReference = () -> linearActiveLabels (items , viewers , VIEW_DISTANCE );
@@ -219,9 +223,10 @@ private void reportVisibilityComparison(String benchmark, String baseline, boole
219223 "{\" benchmark\" :\" %s\" ,\" distribution\" :\" %s\" ,\" seed\" :%d," +
220224 "\" items\" :%d,\" viewers\" :%d," +
221225 "\" range\" :%.1f,\" baseline\" :\" %s\" ,\" baselineUsesGrid\" :%b," +
222- "\" candidate\" :\" production-primitive-viewer-index\" ," +
226+ "\" candidate\" :\" production-bounded- primitive-viewer-index\" ," +
223227 "\" candidateStorage\" :\" primitive-soa\" ," +
224228 "\" indexRebuiltPerOperation\" :true,\" candidateUsesGrid\" :false," +
229+ "\" candidateUsesBounds\" :true," +
225230 "\" sampleTargetNs\" :%d,\" warmupRounds\" :%d,\" measurementRounds\" :%d," +
226231 "\" roundOrder\" :\" %s\" ," +
227232 "\" baselineMedianNs\" :%d,\" baselineP95Ns\" :%d," +
@@ -265,6 +270,24 @@ private static List<Point> randomPoints(Random random, int count, double offset,
265270 return points ;
266271 }
267272
273+ /**
274+ * Places viewers around an empty central region. From eight viewers onward the item region is
275+ * enclosed by the viewer AABB, while every viewer remains well beyond the visibility radius.
276+ * This prevents an outer-bounds fast rejection from disguising worst-case miss scans.
277+ */
278+ private static List <Point > enclosingRingPoints (Random random , int count ) {
279+ List <Point > points = new ArrayList <>(count );
280+ double phase = random .nextDouble (2.0D * Math .PI );
281+ for (int index = 0 ; index < count ; index ++) {
282+ double angle = phase + 2.0D * Math .PI * index / Math .max (1 , count );
283+ points .add (new Point (index ,
284+ 512.0D + Math .cos (angle ) * 300.0D ,
285+ 64.0D + random .nextDouble (32.0D ),
286+ 512.0D + Math .sin (angle ) * 300.0D ));
287+ }
288+ return points ;
289+ }
290+
268291 private static long linearActiveLabels (List <Point > items , List <Point > viewers , double range ) {
269292 List <Point > viewerSnapshot = new ArrayList <>(viewers .size ());
270293 for (Point viewer : viewers ) {
0 commit comments