static void Main(string[] args) { // supplying a custom error handler to SDK initialisation // note that a simple messagebox error handler will be supplied, by default // but you should probably provide a custom error callback that interfaces directly with application side error reporting and logging functionality // this example code shows how to implement a custom error callback that directs error information to console output PathEngine.PathEngine pathEngine = DLLManagement.loadDLL("PathEngine", new ConsoleErrorHandler()); // querying SDK version attributes { int major, minor, internalRelease; pathEngine.getReleaseNumbers(out major, out minor, out internalRelease); Console.WriteLine("getReleaseNumbers returns {0}.{1}.{2}", major, minor, internalRelease); } String[] versionAttributes = pathEngine.getVersionAttributes(); Console.WriteLine("version attributes:"); for (int i = 0; i < versionAttributes.Length; i += 2) { Console.WriteLine("{0} = {1}", versionAttributes[i], versionAttributes[i + 1]); } Console.WriteLine("(end of version attributes)"); // provoke a non fatal error, and null object return // The error handling philosophy in PathEngine is that code should be set up so that errors should not occur, // so the API provides methods to validate data where relevant, and where data is validated correctly you shouldn't see any errors. int[] shapeCoords = { -10, -10, -10, 10, 10, 10, 10, -10 }; shapeCoords[0] = 100; // bad coordinate bool valid = pathEngine.shapeIsValid(shapeCoords); Console.WriteLine("shapeIsValid returns {0}", valid); // The following call to newShape() is not considered good coding practice, then. // Instead application code should use shapeIsValid() (as above) to ensure that newShape() isn't called with bad coordinates. // But we use this here to provoke a 'NonFatal' error, so that we can see this being passed to the application side error handler. // In this case PathEngine will handle the error gracefully, and you should get an error posted to the supplied error handler callback, and a null object returned, // but in other cases, PathEngine may emit 'Fatal' errors on invalid data, and then crash after the error callback returns! Shape shape = pathEngine.newShape(shapeCoords); // will generate a NonFatal Error Console.WriteLine("shape.isNull() returns {0}", shape.isNull()); shapeCoords[0] = -10; // fix the bad coordinate Console.WriteLine("(coordinates fixed)"); valid = pathEngine.shapeIsValid(shapeCoords); Console.WriteLine("shapeIsValid returns {0}", valid); shape = pathEngine.newShape(shapeCoords); Console.WriteLine("shape.isNull() returns {0}", shape.isNull()); // using the FaceVertexMesh callback to generate a simple square ground mesh FaceVertexMesh[] contentMeshes = new FaceVertexMesh[1]; contentMeshes[0] = new SquareMesh(); Mesh mesh = pathEngine.buildMeshFromContent(contentMeshes, new String[0]); Console.WriteLine("mesh built from content, getNumberOf3DFaces returns {0}", mesh.getNumberOf3DFaces()); // this time we generate unobstructed space preprocess only // (this enables collision queries for the agent shape, pathfind preprocess is not required for the following) mesh.generateUnobstructedSpaceFor(shape, false, new String[0]); // place an agent and add to a collision context Position pos = mesh.generateRandomPosition(); Agent placedAgent = mesh.placeAgent(shape, pos); CollisionContext context = mesh.newContext(); context.addAgent(placedAgent); Console.WriteLine("context getNumberOfAgents() returns {0}", context.getNumberOfAgents()); // call getAllAgentsOverlapped // (this shows the linkage for an array out argument, and also gives as another handle to compare to placedAgent) Agent[] overlapped; mesh.getAllAgentsOverlapped(shape, context, pos, out overlapped); Console.WriteLine("number of agents overlapped = {0}", overlapped.Length); // we can't compare interface object handles directly, but a getComparisonToken() method is supplied for this purpose // (and can also be used for sorting, if this is required) Console.WriteLine("placedAgent.getComparisonToken() returns {0}", placedAgent.getComparisonToken()); foreach (Agent overlappedAgent in overlapped) { Console.WriteLine("overlappedAgent.getComparisonToken() returns {0}", overlappedAgent.getComparisonToken()); } // a simple file output stream callback is supplied OutputStream os = new FileOutputStream("savedMesh.xml"); mesh.saveGround("xml", false, os); // object lifetime notes { Mesh mesh2 = pathEngine.buildMeshFromContent(contentMeshes, new String[0]); // ** PathEngine interface objects are not garbage collected, so mesh2 will not be cleaned up automatically // ** and will therefore now be leaked, unless pathEngine.deleteAllObjects() is called } mesh.destroy(); // clean up this interface object explicitly // ** but don't forget that the interface object is now no longer valid, and methods should not be called on this object // ** and note that dependant objects such as placed agents and collision contexts are also destroyed with the mesh pathEngine.deleteAllObjects(); // cleans up all objects created by PathEngine Console.WriteLine("(completed, press enter)"); Console.ReadLine(); }
static void Main(string[] args) { PathEngine.PathEngine pathEngine = DLLManagement.loadDLL("PathEngine"); // load a ground mesh byte[] meshBuffer = System.IO.File.ReadAllBytes("../resource/meshes/mesh1.xml"); string[] loadingOptions = {}; Mesh mesh = pathEngine.loadMeshFromBuffer("xml", meshBuffer, loadingOptions); // create a pathfinding agent shape Shape shape; { int[] coordinateData = { -10, -10, -10, 10, 10, 10, 10, -10 }; shape = pathEngine.newShape(coordinateData); } // generate preprocess for this agent shape string[] noOptions = { }; mesh.generateUnobstructedSpaceFor(shape, true, noOptions); mesh.generatePathfindPreprocessFor(shape, noOptions); // generate random unobstructed positions for query start and end // collision contexts provide dynamic state // default constructed API object references act like null pointers to API objects in the native mapping // and null collision context arguments are used in the API to indicate no dynamic state CollisionContext nullContext; Position start; do { start = mesh.generateRandomPosition(); }while(mesh.testPointCollision(shape, nullContext, start)); Console.WriteLine("start: {0}:{1},{2})", start.cell, start.x, start.y); Position goal; do { goal = mesh.generateRandomPosition(); }while(mesh.testPointCollision(shape, nullContext, goal)); Console.WriteLine("goal: {0}:{1},{2})", goal.cell, goal.x, goal.y); // pathfind! Path path = mesh.findShortestPath(shape, nullContext, start, goal); if (path.isNull()) { Console.WriteLine("No unobstructed path exists between start and goal."); } else { Console.WriteLine("Path found with {0} points:", path.size()); for (int i = 0; i < path.size(); ++i) { Position p = path.position(i); Console.WriteLine("{0}:{1},{2}", p.cell, p.x, p.y); } } Console.WriteLine("(completed, press enter)"); Console.ReadLine(); }