In a pathfinding algorithm you generally don’t look at steps but distances and costs, unless for some specific reason you need to know the steps to target, in which case you could use the cost.
For this problem we need to measure the edges lengths to find either the shortest or the longest path.
Here is how I would approach this, which is basically the same as what Denis posted:
# Get edges of vertex1
# Get edges of vertex2
# Multiply both edges and you get the loop
# Determine if it is a closed or open loop
# Starting with vertex1 run the edge loop in one direction
# If it is an open loop:
# If we hit vertex2 we are done, convert edges to vertex.
# if we reach the end, run the loop in the opposite direction and you'll find vertex2
# If it is a closed loop:
# If we hit vertex 2 then get the traveled distance
# Get the distance of the inverted edges
# We have both path, pick up one and convert to vertex.
This method works only with simple loops. If the two vertices does not share the common loop than this method will fail. That’s why it would be good to know what result we need.
i’ve wanted to practice a little in mxs this morning
here are two methods implemented – search best by distance and direction
method #1 picks an edge with second vertex closest to the target point
method #2 picks an edge which looks straighter at the target point
global connectPointsDialogPos = if connectPointsDialogPos == undefined then unsupplied else connectPointsDialogPos
try(destroydialog connectPointsDialog) catch()
rollout connectPointsDialog "Connect Verts by denisT" width:200
(
fn getVertEdges node vert =
(
edges = #{}
for k=1 to node.GetVertexEdgeCount vert do append edges (node.GetVertexEdge vert k)
edges
)
fn as_point4 point index =
(
point = point as point4
point.w = index
point
)
fn getEdgeSecondVert node edge first asPoint:on =
(
vv = polyop.getEdgeVerts node edge
if (k = finditem vv first) != 0 do deleteitem vv k
v = vv[1]
if asPoint then as_point4 (polyop.getvert node v) v else v
)
fn getEdgeBestByDistance node first target value: =
(
edges = getVertEdges node first
if value == unsupplied do value = 1e9
best = undefined
for edge in edges do
(
p = getEdgeSecondVert node edge first
d = distance (p as point3) target
if d < value do
(
value = d
best = #(edge, p, value)
)
)
best
)
fn getEdgeDirection node edge first source: normalized:on =
(
if source == unsupplied do source = polyop.getvert node first
p = getEdgeSecondVert node edge first
v = p as point3 - source
if normalized do v = normalize v
as_point4 v p.w
)
fn getEdgeBestByDirection node first target value: =
(
edges = getVertEdges node first
if value == unsupplied do value = 1e9
best = undefined
for edge in edges do
(
source = polyop.getvert node first
p = getEdgeDirection node edge first source:source
d = abs (1 - dot (p as point3) (normalize (target - source)))
if d < value do
(
value = d
best = #(edge, p, value)
)
)
best
)
fn getEdgeBestByLoop node first target value: =
(
)
fn searchConnection node first second method: =
(
verts = #(first)
edges = #{}
out = off
source = polyop.getvert node first
target = polyop.getvert node second
value = distance source target
while not (out or keyboard.escpressed) do
(
best = method node first target --value:value
if best != undefined then
(
v = best[2].w as integer
if finditem verts v > 0 then out = on
else
(
append verts v
append edges best[1]
first = v
value = best[3]
out = (v == second)
)
)
else out = on
)
node.selectededges = edges
--format "best:%
" best
verts
)
fn getNode =
(
if iskindof (node = selection[1]) Editable_Poly and node.selectedverts.count == 2 do node
)
radiobuttons method_rb "Method:" labels:#("Distance", "Direction", "Loop") default:1 align:#center offset:[0,0]
button search_bt "Find Connection" width:192 align:#right offset:[9,0]
on search_bt pressed do undo "Find Connection" on if (node = getNode()) != undefined do
(
first = node.selectedverts[1].index
second = node.selectedverts[2].index
method = #(getEdgeBestByDistance, getEdgeBestByDirection, getEdgeBestByLoop)[method_rb.state]
verts = searchConnection node first second method:method
format "% <-> % = %
" first second verts
)
on connectPointsDialog close do
(
connectPointsDialogPos = getdialogpos connectPointsDialog
)
)
createdialog connectPointsDialog pos:connectPointsDialogPos
the code is not optimized but shows the idea
select two verts of any editable poly
pick a method and press the button
algorithm tries to find a “path” from one point to another and returns step verts, and selects edges as a found path
method #3 – is loop implementation. (be continued… maybe ;))
It’s pretty funny (and really interesting), how different ideas met in this code…
Many people many ideas and a complex solution for every certain situations. (best game ever)
I would rellay like to see how else these problems could be solved. For example along smoothing groups…
I take my hat off to you, denisT.
I can’t follow well your code, but it’s incredible how quick and few instructions you need to solve problems.
In this case, something is brong. At least in the sphere example bellow. Shortest path should be following the smallest latitude at the first vertex level on top, and then following a meridian (as all of them have the same length) or the reverse.
both my algorithms don’t find the shortest path. they are looking for ‘best’ solution of every next step. summary path might be not the shortest
The shortes path would need all the path lengths to be compared, so it would need a pretty high computing power on large meshes, however there must be optimized solutions for these kind of problems, like pre-selecting a hot area that contains the shortest path or flattening the mesh somehow, or flattening the mesh so we can measure the distances by using simple straight lines and converting them back to a vertex or edge level.
So in this situation the only and in this case the best method is always getting the forthcoming element of the loop and measure their length and the least steps that is necessary to reach the target vertex.
Or maybe a two way solution for it, that starts from both vertexes and moving to the direction pointing each other. I have got more ideas but they need to be tested to get an exact result, if they are working or not.
in one of my maya tools i’ve successfully used another concept:
user wants to connect two verts
user exactly knows that these two verts are connectable
user uses the best view to select these two verts
user expects to see ‘connection’ in a view which better displays the result
so i do search using best direction to the target in current view supposing that the first step must be in view center direction (not out).
it works very well in 90% cases
Denis, there is an unhandled case in both methods Distance and Direction:
(
node = converttopoly (box lengthsegs:3 widthsegs:3 heightsegs:3)
node.selectedverts = #{11,27}
)
(
node = converttopoly (teapot segs:4)
node.selectedverts = #{402,486}
)
i believe you… this is not a practical task for me at all. i wrote it in half an hour and didn’t really test. i’ve just wanted to show some ideas.