How to discourage direction changes with AStar - path-finding

Can I make the builtin AStar choose the shortest path with the least direction changes?
I currently build my graph like so:
extends GridMap
var _astar = AStar.new()
func _ready():
var id = 0
for c in get_used_cells():
var weight = 1.0
if _get_cover(c.x, c.y, c.z):
weight = 9999.0 # impassable tile
_astar.add_point(id, Vector3(c.x, c.y, c.z), weight)
id += 1
for c in get_used_cells():
var center = _astar.get_closest_point(Vector3(c.x, c.y, c.z))
var above = _astar.get_closest_point(Vector3(c.x, c.y, c.z + 1))
var right = _astar.get_closest_point(Vector3(c.x + 1, c.y, c.z))
assert(id > 0)
if above >= 0:
_astar.connect_points(center, above, true)
if right >= 0:
_astar.connect_points(center, right, true)
It seems like you can only weight points, not edges, so I'm not sure how to prefer one direction over another.
The path it chooses always seems to maximize direction changes:

When you see 3 Nodes, if the direction is changed, then increase the F value of last Node.
Three Nodes will tell you that the direction changes.

Related

Getting the Vertices numbers from an Edge

I am using the shortest path algorithm from LightGraphs.jl. In the end I want to collect some information about the nodes along the path. In order to do that I need to be able to extract the vertices from the edges that the function gives back.
Using LightGraphs
g = cycle_graph(4)
path = a_star(g, 1, 3)
edge1 = path[1]
Using this I get: Edge 1 => 2
How would I automatically get the vertices 1, 2 without having to look at the Edge manually? I thinking about some thing like edge1[1] or edge1.From which both does not work.
Thanks in advance!
The accessors for AbstractEdge classes are src and dst, used like this:
using LightGraphs
g = cycle_graph(4)
path = a_star(g, 1, 3)
edge1 = path[1]
s = src(edge1)
d = dst(edge1)
println("source: $s") # prints "source: 1"
println("destination: $d") # prints "destination: 2"

How to determine normal vector to an SCNPlane in Apple SceneKit

I have an SCNode which is dynamically created using the SCNPlane geometry to draw a plane using SceneKit.
How do I determine the normal vector to this plane?
Here is a playground demonstrating what I have tried. I have attached a screenshot of the resulting scene that is drawn. I don't think any of the cylinders, which represent the vectors obtained at the normal vector to this red plane.
//: Playground - noun: a place where people can play
import UIKit
import SceneKit
import PlaygroundSupport
// Set up the scene view
let frame = CGRect(
x: 0,
y: 0,
width: 500,
height: 300)
let sceneView = SCNView(frame: frame)
sceneView.showsStatistics = true
sceneView.autoenablesDefaultLighting = true
sceneView.allowsCameraControl = true
sceneView.scene = SCNScene()
// Setup our view into the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 3)
sceneView.scene!.rootNode.addChildNode(cameraNode)
// Add a plane to the scene
let plane = SCNNode(geometry: SCNPlane(width: 3,height: 3))
plane.geometry?.firstMaterial!.diffuse.contents = UIColor.red.withAlphaComponent(0.5)
plane.geometry?.firstMaterial?.isDoubleSided = true
sceneView.scene!.rootNode.addChildNode(plane)
/*
normalSource = [SCNGeometrySource geometrySourceWithData:data
semantic:SCNGeometrySourceSemanticNormal
vectorCount:VERTEX_COUNT
floatComponents:YES
componentsPerVector:3 // nx, ny, nz
bytesPerComponent:sizeof(float)
dataOffset:offsetof(MyVertex, nx)
dataStride:sizeof(MyVertex)];
*/
let dataBuffer = plane.geometry?.sources(for: SCNGeometrySource.Semantic.normal)[0].data
let colorArray = [UIColor.red, UIColor.orange, UIColor.yellow, UIColor.green, UIColor.blue, UIColor.systemIndigo, UIColor.purple, UIColor.brown, UIColor.black, UIColor.systemPink]
let sceneGeometrySource = dataBuffer!.withUnsafeBytes {
(vertexBuffer: UnsafePointer<SCNVector3>) -> SCNGeometrySource in
let sceneVectors = Array(UnsafeBufferPointer(start: vertexBuffer, count: dataBuffer!.count/MemoryLayout<SCNVector3>.stride))
var i=0
for vector in sceneVectors{
let cyl = SCNCylinder(radius: 0.05, height: 3)
cyl.firstMaterial!.diffuse.contents = colorArray[i].withAlphaComponent(0.8)
let lineNode = SCNNode(geometry: cyl)
lineNode.eulerAngles = vector
sceneView.scene!.rootNode.addChildNode(lineNode)
}
return SCNGeometrySource(vertices: sceneVectors)
}
PlaygroundSupport.PlaygroundPage.current.liveView = sceneView
in the apple documentation https://developer.apple.com/documentation/accelerate/working_with_vectors in "Calculate the Normal of a Triangle" you can find the solution. You just need 3 points which are not on one line and then use this:
The following code defines the three vertices of the triangle:
let vertex1 = simd_float3(-1.5, 0.5, 0)
let vertex2 = simd_float3(1, 0, 3)
let vertex3 = simd_float3(0.5, -0.5, -1.5)
Your first step in calculating the normal of the triangle is to create two vectors defined by the difference between the vertices—representing two sides of the triangle:
let vector1 = vertex2 - vertex3
let vector2 = vertex2 - vertex1
The simd_cross function returns the vector that's perpendicular to the two vectors you pass it. In this example, the returned vector is the normal of the triangle. Because the normal represents a direction, you can normalize the value to get a unit vector:
let normal = simd_normalize(simd_cross(vector1, vector2))

DFS to get all possible solutions?

I have these Circles:
I want to get the list of all possible solution of maximum non-intersecting circles. This is the illustration of the solution I wanted from node A.
Therefore the possible solutions from node A:
1 = [A,B,C], 2 = [A,B,E], 3 = [A,C,B], 4 = [A,E,B] ..etc
I want to store all of the possibilities into a list, which the will be used for weighting and selecting the best result. However, I'm still trying to create the list of all possibilities.
I've tried to code the structure here, however I still confused about backtracking and recursive. Anyone could help here?
# List of circle
# List of circle
list_of_circle = ['A','B','C','D','E']
# List of all possible solutions
result = []
# List of possible nodes
ways = []
for k in list_of_circle:
if len(list_of_circle)==0:
result.append(ways)
else:
ways.append[k]
list_of_circle.remove(k)
for j in list_of_circle:
if k.intersects(j):
list_of_circle.remove(j)
return result
Here is a possible solution (pseudocode).
def get_max_non_intersect(selected_circles, current_circle_idx, all_circles):
if current_circle_idx == len(all_circles): # final case
return selected_circles
# we recursively get the biggest selection of circles if the current circle is not selected
list_without_current_circle = get_max_non_intersect(selected_circles, current_circle_idx + 1, all_circles)
# now we check if we can add the current circle to the ones selected
current_intersects_selected = false
current_circle = all_circles[current_circle_idx]
for selected_circle in selected_circles:
if intersects(current_circle, selected_circle):
current_intersects_selected = true
break
if current_intersects_selected is true: # we cannot add the current circle
return list_without_current_circle
else: # we can add the current circle
list_with_current_circle = get_max_non_intersect(selected_circles + [current_circle], current_circle_idx + 1, all_circles)
return list_with_current_circle + list_without_current_circle

Algorithm to make a route from Source Node to End Node using every node exactly once

I'm trying to create a route, given a start node and end node, that will travel to every single node in the graph, and minimize the cost of doing so.
The graph is undirected, and every node is connected to each other directly. The weight of every edge is positive. I think because every node connects to eachother, that there are many "loops" in my graph, but I don't want to generate a route with a loop in it.
So, for a graph with N nodes, I have (N*N-1) directed edges. A graph with nodes A,B,C,D would have edges:
A to B / B to A
A to C / C to A
A to D / D to A
B to C / C to B
C to D / D to C
B to D / D to B
When I implement the Floyd Warshall algorithm from Wikipedia, I only ever get an array of 2 nodes. There's a function in the article that gives you the shortest path from node U to node V, and that's the function that only returns [U,V] (array containing U and V)
I MUST be misunderstanding what it is exactly that Floyd Warshall is meant to solve. I'll attach my code to show how I've implemented it in javascript.
function colorsToEdgeMatrix(colors){
var dist = [];
for(var i = 0; i < colors.length;i++){
dist[i] = [];
var c1 = colors[i];
for(var j = 0; j < colors.length;j++){
if(i == j){continue;}
var c2 = colors[j];
dist[i][j] = colorDistance(c1,c2);
}
}
return dist;
}
function colorsToNextMatrix(colors){
var next = [];
for(var i = 0; i < colors.length;i++){
next[i] = [];
for(var j = 0; j < colors.length;j++){
if(i == j){continue;}
next[i][j] = j;
}
}
return next;
}
//lab colors
function FloydWarshallWithPathReconstruction (colors){
var next = [];
var dist = colorsToEdgeMatrix(colors);
var next = colorsToNextMatrix(colors);
var N = colors.length;
for(var k = 0; k < N; k++){ // standard Floyd-Warshall implementation
for(var i = 0; i < N; i++){
for(var j = 0; j < N; j++){
if(dist[i][k] + dist[k][j] < dist[i][j]){
dist[i][j] = dist[i][k] + dist[k][j]
next[i][j] = next[i][k]
}
}
}
}
return next;
}
function Path(next,u, v) {
var path = [];
if(next[u][v] == null){
return []
}
path = [u]
while(u != v){
u = next[u][v]
path.push(u)
}
return path;
}
var lab = randomLABArray(100); //make an array of LAB color space colors. a LAB element has an array structure [L,a,b]
lab = sortLuminosityLAB(lab); //sorts the LAB colors from light to dark
var next = FloydWarshallWithPathReconstruction(lab); //gets all paths using floyd warshall
var path = Path(next, 0, lab.length-1); //gets the path calculated from lightest to darkest
console.log( path );
Does this algorithm not necessarily return a path that goes through every node? I guess what it does is just spits out the best path for every start and end node, and doesn't guarantee any path goes through every node...
I used the Nearest Neighbor algorithm with decent result, and Brute Force is impossible after 10 elements. I was hoping the Floyd Warshall would give even better results
Huh...so this might actually be a Hamiltonian Path problem and isn't as simple as I thought...
This can be reduced to the Traveling Salesman problem as follows. Pick a large number M which is greater than the sum of all weights in the graph. Add this number to the weights on all edges in the graph except the edge connecting the start node and the end node. That edge should have its cost set to zero. Solve the resulting Traveling Salesman Problem. It is easy to see that the optimal solution of the TSP will include the edge connecting the start and end node. Throw that edge away from the optimal solution and adjust the weights back to their original value -- and you have found the optimal solution to your problem.
Conversely, the regular TSP can be reduced to your problem in an even easier way. Pick a node at random and duplicate it. Let one of these newly duplicated nodes be the start node and the other be the end node. Solve your optimal path problem for this instance. Then -- remerge these two nodes into the original node, which will splice the ends together to form a circuit, which is easily seen to be optimal. This confirms your intuition that the problem is at least as hard as the Hamiltonian circuit problem.

Find specific point between 2 points - three.js

How can I find a point ( C (x,y,z) ) between 2 points ( A(x,y,z) , B(x,y,z) ) in a thgree.js scene?
I know that with this: mid point I can find the middle point between them, but I don't want the middle point, I want to find the point which is between them and also has distance a from the A point?
in this picture you can see what I mean :
Thank you.
Basically you need to get the direction vector between the two points (D), normalize it, and you'll use it for getting the new point in the way: NewPoint = PointA + D*Length.
You could use length normalized (0..1) or as an absolute value from 0 to length of the direction vector.
Here you can see some examples using both methods:
Using absolute value:
function getPointInBetweenByLen(pointA, pointB, length) {
var dir = pointB.clone().sub(pointA).normalize().multiplyScalar(length);
return pointA.clone().add(dir);
}
And to use with percentage (0..1)
function getPointInBetweenByPerc(pointA, pointB, percentage) {
var dir = pointB.clone().sub(pointA);
var len = dir.length();
dir = dir.normalize().multiplyScalar(len*percentage);
return pointA.clone().add(dir);
}
See it in action: http://jsfiddle.net/8mnqjsge/
Hope it helps.
I know the question is for THREE.JS and I end up looking for something similar in Babylon JS.
Just in case if you are using Babylon JS Vector3 then the formula would translate to:
function getPointInBetweenByPerc(pointA, pointB, percentage) {
var dir = pointB.clone().subtract(pointA);
var length = dir.length();
dir = dir.normalize().scale(length *percentage);
return pointA.clone().add(dir);
}
Hope it help somebody.
This is known as lerp between two points
e.g. in Three:
C = new Three.Vector3()
C.lerpVectors(A, B, a)
also in generic this is just a single lerp (linear interpolation) math (basically (a * t) + b * (1 - t)) on each axis. Lerp can be described as follows:
function lerp (a, b, t) {
return a + t * (b - a)
}
in your case (see above) :
A = {
x: lerp(A.x, B.x, a),
y: lerp(A.y, B.y, a),
z: lerp(A.z, B.z, a)
}

Resources