@@ -408,7 +408,7 @@ The collision map can only have 4 colors:
408408This is an internal method. Don't use it if you don't know what you are doing.
409409```
410410
411- It's hard to go into detail on how this works but if you want to see the result
411+ How it works in detail is quite technical but if you want to see the result
412412run this example code:
413413```pascal
414414{$I WaspLib/osrs.simba}
@@ -440,10 +440,11 @@ var
440440 doorMapA, doorMapB: TIntegerMatrix;
441441 connectA, connectB: TIntegerArray;
442442 minRadius: Boolean;
443+ timer: TCountDown;
443444begin
444445 minLen := Self.MinimumTiles * RSTranslator.TileArea;
445446
446- Self.WhiteClusters := white.Cluster(1);
447+ Self.WhiteClusters := white.Cluster(1).SortBySize(True) ;
447448 Self.Doors := Self.FindDoors(red.Cluster(1.5), map);
448449
449450 SetLength(connectA, Length(Self.Doors));
@@ -462,18 +463,24 @@ begin
462463 begin
463464 if Length(Self.WhiteClusters[i]) < minLen then
464465 Continue;
465-
466466 for pt in Self.WhiteClusters[i] do
467467 Self.Matrix[pt.Y, pt.X] := i;
468468 end;
469469
470470 for i := 0 to High(Self.Doors) do
471471 Result.Nodes += Self.ProcessDoors(Self.Doors[i], i, n, doorMapA, doorMapB);
472472
473+ timer.Start(4 * ONE_SECOND);
473474 SetLength(Result.Paths, Length(Result.Nodes));
474475
475476 for i := 0 to High(Self.WhiteClusters) do
476477 begin
478+ if timer.IsFinished or (i = 0) or (i = High(Self.WhiteClusters)) then
479+ begin
480+ WriteLn GetDebugLn('Generating webgraph part ' + ToStr(i) + ' of ' + ToStr(High(Self.WhiteClusters)));
481+ timer.Restart();
482+ end;
483+
477484 if not minRadius then
478485 begin
479486 Self.ProcessSmallCluster(Result, minRadius, doorMapA[i], doorMapB[i], i, minLen, connectA, connectB);
511518 i, j: Integer;
512519 t: UInt64;
513520begin
514- WriteLn GetDebugLn('Generating webgraph for region : ' + name + ' this can take a few seconds.');
521+ WriteLn GetDebugLn('Generating webgraph: ' + name + ' this can take a few seconds.');
515522 t := GetTimeRunning();
516523
517524 white := map.FindColor($FFFFFF, 0);
@@ -545,6 +552,113 @@ begin
545552 WriteLn GetDebugLn('WebGraphGenerator', 'Generating webgraph took ' + ToStr(Round(((GetTimeRunning()-t)/1000), 2)) + ' seconds.', ELogLevel.SUCCESS);
546553end;
547554
555+ (*
556+ ## Webgraph Generation
557+ If you do wish to understand the technical details a little bit more, the
558+ following is a simplified explanation with images of more or less how it works.
559+
560+ First of all, you need to have a collision map. WaspLib's webgraph generator
561+ assumes the walking space is white and that the doors are red, other than that,
562+ it doesn't really matter what colors your collision map, for this explanation
563+ I'm going to use a small piece of varrock with a bit of the wilderness:
564+ ```{figure} ../../images/graphgen0.png
565+ ```
566+
567+ We start off by extracting all the white:
568+ ```{figure} ../../images/graphgen1.png
569+ ```
570+
571+ Then, we cluster the white, grouping each white pixel that is within any other
572+ white pixel horizontal or vertically in the same cluster. It's important to not
573+ include diagonal pixels or your clusters will cross certain walls, at least in
574+ WaspLib's collision maps. We also sort our clusters by size as we can have some
575+ performance improvements by having the clusters sorted.
576+
577+ Doing this will look something like this:
578+ ```{figure} ../../images/graphgen2.png
579+ ```
580+
581+ We also need to find all the red to know where the doors are, in this image I've
582+ expanded the color a little so it's visble but you should only get the door:
583+ ```{figure} ../../images/graphgen3.png
584+ ```
585+
586+ While doing this, you also want to get and store for later the point in front
587+ and behind the door and map those points to each of your clusters.
588+
589+ The next step is to start processing our clusters. Because we sorted them by size
590+ we start by skipping very small ones, usually clusters that are less than the
591+ size of a tile.
592+
593+ Clusters that are less than `WebGraphGenerator.MinimumTiles` we add a single node
594+ in the middle, it's a cluster too small to be worth extra processing.
595+ Which would be the red nodes on the image below:
596+ ```{figure} ../../images/graphgen4.png
597+ ```
598+
599+ We also check our mapped doors to see if any of the points in front or behind
600+ each door belongs to our cluster, if it does, we connect it to our node.
601+
602+ Then we start processing bigger clusters if you have
603+ `WebGraphGenerator.Skeletonize` set to `True` which is the default, we will
604+ sekeletonize the cluster which should look something like this:
605+ ```{figure} ../../images/graphgen5.png
606+ ```
607+
608+ And then we partition it with `WebGraphGenerator.Spacing`:
609+ ```{figure} ../../images/graphgen6.png
610+ ```
611+
612+ If you have `WebGraphGenerator.Skeletonize` set to `False`, we simply parition
613+ the cluster as it is, again with `WebGraphGenerator.Spacing`.
614+
615+ It's hard to see much difference here but it's much denser than the above and
616+ later on you will see the actual difference when paths are added:
617+ ```{figure} ../../images/graphgen7.png
618+ ```
619+
620+ Whichever case your settings followed, those will be your nodes for that cluster.
621+
622+ Then next step is to try and connect the nodes we just created by proximity.
623+ We check `WebGraphGenerator.MaxConnections*2` closest nodes to each node and
624+ connect up to `WebGraphGenerator.MaxConnections` if:
625+ - We have a straight path between the 2 nodes
626+ - If we can have a path using AStar
627+
628+ It should look something like this:
629+ ```{figure} ../../images/graphgen8.png
630+ ```
631+
632+ For AStar path finding we use the original skeleton/cluster and this is an
633+ example of a connection where AStar was used:
634+ ```{figure} ../../images/graphgen9.png
635+ ```
636+ As you can see that crossing over the wilderness river crossing black, it's
637+ connected because AStar has found a path around it. That's also what's happening
638+ on those nodes around trees with lines crossing the trees, there's a valid path
639+ because AStar found a way around.
640+
641+ If you were to have `WebGraphGenerator.Skeletonize` set to `False`, this is what
642+ the same thing would look like:
643+ ```{figure} ../../images/graphgen10.png
644+ ```
645+
646+ Lastly, we our mapped doors that has their front or behind point within our
647+ cluster and connect that door to the closest
648+ `WebGraphGenerator.MaxDoorConnections` amount of nodes:
649+ ```{figure} ../../images/graphgen11.png
650+ ```
651+
652+ And that's about it. The final graph should look like this if you
653+ `WebGraphGenerator.Skeletonize` set to `True`, which again, is the default:
654+ ```{figure} ../../images/graphgen12.png
655+ ```
656+
657+ And this would be `WebGraphGenerator.Skeletonize` set to `False`:
658+ ```{figure} ../../images/graphgen13.png
659+ ```
660+ *)
661+
548662var
549663(*
550664## WebGraphGenerator variable
0 commit comments