mirror of
https://github.com/UnickSoft/graphonline.git
synced 2026-02-16 10:40:57 +00:00
Change script location.
Split js code. Added cache and changed loading mechanism for js sources.
This commit is contained in:
35
script/features/algorithms/api/index.js
Normal file
35
script/features/algorithms/api/index.js
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
let modulDir = "features/algorithms/";
|
||||
|
||||
doInclude ([
|
||||
include ("model/Algorithms.js", modulDir),
|
||||
include ("model/BaseTraversal.js", modulDir)
|
||||
])
|
||||
|
||||
function loadAsyncAlgorithms(onFinish) {
|
||||
let pluginsList = ["BFS.js",
|
||||
"Coloring.js",
|
||||
"ConnectedComponent.js",
|
||||
"DFS.js",
|
||||
"EulerianLoop.js",
|
||||
"EulerianPath.js",
|
||||
"FindAllPatches.js",
|
||||
"FindLongestPath.js",
|
||||
"FindShortPatchsFromOne.js",
|
||||
"Floid.js",
|
||||
"GraphReorder.js",
|
||||
"HamiltonianLoop.js",
|
||||
"HamiltonianPath.js",
|
||||
"IsomorphismCheck.js",
|
||||
"MaxClique.js",
|
||||
"MaxFlow.js",
|
||||
"MinimumSpanningTree.js",
|
||||
"ModernGraphStyle.js",
|
||||
"RadiusAndDiameter.js",
|
||||
"ShortestPath.js",
|
||||
"VerticesDegree.js"];
|
||||
|
||||
doIncludeAsync (pluginsList.map((plugin) => include ("model/plugins/" + plugin, modulDir)), onFinish);
|
||||
}
|
||||
|
||||
}
|
||||
305
script/features/algorithms/model/Algorithms.js
Normal file
305
script/features/algorithms/model/Algorithms.js
Normal file
@@ -0,0 +1,305 @@
|
||||
/**
|
||||
* File for algorithms.
|
||||
*
|
||||
*/
|
||||
|
||||
// Return list of 'vertex = [connected vertices]'
|
||||
function getVertexToVertexArray(graph, ignoreDirection)
|
||||
{
|
||||
res = {};
|
||||
|
||||
for (var i = 0; i < graph.edges.length; i ++)
|
||||
{
|
||||
edge = graph.edges[i];
|
||||
if (!res.hasOwnProperty(edge.vertex1.id))
|
||||
{
|
||||
res[edge.vertex1.id] = [];
|
||||
}
|
||||
res[edge.vertex1.id].push(edge.vertex2);
|
||||
if (!edge.isDirect || ignoreDirection)
|
||||
{
|
||||
if (!res.hasOwnProperty(edge.vertex2.id))
|
||||
{
|
||||
res[edge.vertex2.id] = [];
|
||||
}
|
||||
|
||||
res[edge.vertex2.id].push(edge.vertex1);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Global array of all algorithms.
|
||||
var g_Algorithms = [];
|
||||
var g_AlgorithmIds = [];
|
||||
|
||||
// Call this function to register your factory algorithm.
|
||||
function RegisterAlgorithm (factory)
|
||||
{
|
||||
g_Algorithms.push(factory);
|
||||
g_AlgorithmIds.push(factory(null).getId());
|
||||
}
|
||||
|
||||
// Base algorithm class.
|
||||
function BaseAlgorithm (graph, app)
|
||||
{
|
||||
this.graph = graph;
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
// @return name of algorithm. For now we supports only 2 locals: "ru" and "en"
|
||||
BaseAlgorithm.prototype.getName = function(local)
|
||||
{
|
||||
return "unknown_name_" + local;
|
||||
}
|
||||
|
||||
// @return id of algorithm. Please use format: "your id"."algorithm id". Ex. "OlegSh.ConnectedComponent"
|
||||
BaseAlgorithm.prototype.getId = function()
|
||||
{
|
||||
return "unknown.unknown";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
BaseAlgorithm.prototype.getMessage = function(local)
|
||||
{
|
||||
return "unknown_message_" + local;
|
||||
}
|
||||
|
||||
// calls when user select vertex.
|
||||
// @return true if you allow to select this object or false.
|
||||
BaseAlgorithm.prototype.selectVertex = function(vertex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// calls when user select edge.
|
||||
// @return true if you allow to select this object or false.
|
||||
BaseAlgorithm.prototype.selectEdge = function(edge)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// user click to workspace.
|
||||
// @return true if you allow to deselect all
|
||||
BaseAlgorithm.prototype.deselectAll = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// get result of algorithm.
|
||||
// If result if not ready, please return null.
|
||||
// It will be called after each user action.
|
||||
// Please return true, if you done.
|
||||
BaseAlgorithm.prototype.result = function(resultCallback)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// If you no need to get feedback from user, return true.
|
||||
// In this case result will calls once.
|
||||
BaseAlgorithm.prototype.instance = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// @return false, if you change up text and do not want to restore it back.
|
||||
BaseAlgorithm.prototype.needRestoreUpText = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// @return true, if you change restore graph after use.
|
||||
BaseAlgorithm.prototype.wantRestore = function()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// calls this method if wantRestore return true.
|
||||
BaseAlgorithm.prototype.restore = function()
|
||||
{
|
||||
}
|
||||
|
||||
// @return 0, if object is not selected, in other case return groupe of selection.
|
||||
BaseAlgorithm.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This method is called, when messages was updated on html page.
|
||||
BaseAlgorithm.prototype.messageWasChanged = function() {}
|
||||
|
||||
// Algorithm priority in menu
|
||||
BaseAlgorithm.prototype.getPriority = function()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Algorithm support multi graph
|
||||
BaseAlgorithm.prototype.IsSupportMultiGraph = function()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BaseAlgorithm.prototype.getCategory = function()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default handler.
|
||||
* Select using mouse, drag.
|
||||
*
|
||||
*/
|
||||
function BaseAlgorithmEx(graph, app)
|
||||
{
|
||||
BaseAlgorithm.apply(this, arguments);
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
BaseAlgorithmEx.prototype = Object.create(BaseAlgorithm.prototype);
|
||||
|
||||
BaseAlgorithmEx.prototype.CalculateAlgorithm = function(algorithmName, otherParams, resultCallback, ignoreSeparateNodes = false)
|
||||
{
|
||||
if (location.hostname === "localhost" || location.hostname === "127.0.0.1")
|
||||
console.log(algorithmName + " " + otherParams);
|
||||
|
||||
var graph = this.graph;
|
||||
var ignoreNodes = {};
|
||||
|
||||
if (ignoreSeparateNodes)
|
||||
for (var i = 0; i < graph.vertices.length; i++)
|
||||
if (!graph.HasConnectedNodes(graph.vertices[i]))
|
||||
ignoreNodes[graph.vertices[i].id] = 1;
|
||||
|
||||
var creator = new GraphMLCreator(graph.vertices, graph.edges, ignoreNodes);
|
||||
var pathObjects = [];
|
||||
var properties = {};
|
||||
var result = [];
|
||||
|
||||
var xml = creator.GetXMLString();
|
||||
console.log(xml);
|
||||
|
||||
var processResult = function (msg) {
|
||||
console.log(msg);
|
||||
$('#debug').text(msg);
|
||||
xmlDoc = $.parseXML( msg );
|
||||
var $xml = $( xmlDoc );
|
||||
|
||||
$results = $xml.find( "result" );
|
||||
|
||||
$results.each(function(){
|
||||
$values = $(this).find( "value" );
|
||||
|
||||
$values.each(function(){
|
||||
var type = $(this).attr('type');
|
||||
var value = $(this).text();
|
||||
var res = {};
|
||||
res.type = type;
|
||||
res.value = value;
|
||||
result.push(res);
|
||||
});
|
||||
});
|
||||
|
||||
$nodes = $xml.find( "node" );
|
||||
|
||||
$nodes.each(function(){
|
||||
var id = $(this).attr('id');
|
||||
$data = $(this).find("data");
|
||||
$data.each(function(){
|
||||
if ("hightlightNode" == $(this).attr('key') && $(this).text() == "1")
|
||||
{
|
||||
pathObjects.push(graph.FindVertex(id));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!properties[id])
|
||||
{
|
||||
properties[id] = {};
|
||||
}
|
||||
properties[id][$(this).attr('key')] = $(this).text();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$edges = $xml.find( "edge" );
|
||||
|
||||
$edges.each(function(){
|
||||
var source = $(this).attr('source');
|
||||
var target = $(this).attr('target');
|
||||
var edge = graph.FindEdge(source, target);
|
||||
if (typeof $(this).attr('id') !== 'undefined')
|
||||
{
|
||||
edge = graph.FindEdgeById($(this).attr('id'));
|
||||
}
|
||||
pathObjects.push(edge);
|
||||
|
||||
$data = $(this).find("data");
|
||||
$data.each(function(){
|
||||
if (!properties[edge.id])
|
||||
{
|
||||
properties[edge.id] = {};
|
||||
}
|
||||
properties[edge.id][$(this).attr('key')] = $(this).text();
|
||||
});
|
||||
});
|
||||
|
||||
console.log(result);
|
||||
|
||||
resultCallback(pathObjects, properties, result);
|
||||
};
|
||||
|
||||
if (this.app.isSupportEmscripten()) {
|
||||
console.log("Use Emscripten");
|
||||
var delimiter = "<s\\emscript_split\\s>";
|
||||
var processData = algorithmName + delimiter + xml +
|
||||
delimiter + "report" + delimiter + "xml";
|
||||
otherParams.forEach ( (param) => processData += delimiter + param.name + delimiter + param.value);
|
||||
var res = this.app.processEmscripten(processData);
|
||||
processResult(res);
|
||||
} else {
|
||||
console.log("Use new CGI");
|
||||
var queryString = algorithmName + "=cgiInput&report=xml";
|
||||
otherParams.forEach ( (param) => queryString += "&" + param.name + "=" + param.value);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/" + SiteDir + "cgi-bin/GraphCGI.exe?" + queryString,
|
||||
data: xml,
|
||||
dataType: "text",
|
||||
})
|
||||
.done(function( msg )
|
||||
{
|
||||
processResult(msg);
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BaseAlgorithmEx.prototype.GetNodesPath = function(array, start, count)
|
||||
{
|
||||
var res = [];
|
||||
for (var index = start; index < start + count; index++)
|
||||
{
|
||||
if (array[index].type == 4)
|
||||
{
|
||||
res.push(array[index].value);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
BaseAlgorithmEx.prototype.GetNodesEdgesPath = function(array, start, count)
|
||||
{
|
||||
var res = [];
|
||||
for (var index = start; index < start + count; index++)
|
||||
{
|
||||
if (array[index].type == 4 || array[index].type == 5)
|
||||
{
|
||||
res.push(array[index].value);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
56
script/features/algorithms/model/BaseTraversal.js
Normal file
56
script/features/algorithms/model/BaseTraversal.js
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Find short path.
|
||||
*
|
||||
*/
|
||||
function BaseTraversal(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
this.visited = [];
|
||||
this.edges = [];
|
||||
this.timer = null;
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
BaseTraversal.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
// timer interval
|
||||
BaseTraversal.prototype.timerInterval = 500;
|
||||
|
||||
BaseTraversal.prototype.result = function(resultCallback)
|
||||
{
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BaseTraversal.prototype.selectVertex = function(vertex)
|
||||
{
|
||||
this.visited = [];
|
||||
this.edges = [];
|
||||
|
||||
if (this.timer)
|
||||
clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
|
||||
this.visited.push(vertex);
|
||||
|
||||
var context = this;
|
||||
this.timer = setInterval(function()
|
||||
{
|
||||
context.step();
|
||||
}, this.timerInterval);
|
||||
|
||||
this.message = this.getMainMessage();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BaseTraversal.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (this.visited.includes(object) ? 1 : (this.edges.includes(object) ? 1 : 0));
|
||||
}
|
||||
|
||||
BaseTraversal.prototype.instance = function()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
125
script/features/algorithms/model/plugins/BFS.js
Normal file
125
script/features/algorithms/model/plugins/BFS.js
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Find short path.
|
||||
*
|
||||
*/
|
||||
function BFSAlgorithm(graph, app)
|
||||
{
|
||||
BaseTraversal.apply(this, arguments);
|
||||
this.message = g_startTraversal;
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
BFSAlgorithm.prototype = Object.create(BaseTraversal.prototype);
|
||||
// timer interval
|
||||
BFSAlgorithm.prototype.timerInterval = 500;
|
||||
|
||||
BFSAlgorithm.prototype.getName = function(local)
|
||||
{
|
||||
return g_BFSName;// local == "ru" ? "Поиск в ширину" : "Breadth-first search";
|
||||
}
|
||||
|
||||
BFSAlgorithm.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.BFSAlgorithm";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
BFSAlgorithm.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
BFSAlgorithm.prototype.getCategory = function()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
BFSAlgorithm.prototype.result = function(resultCallback)
|
||||
{
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BFSAlgorithm.prototype.getMainMessage = function()
|
||||
{
|
||||
var message = g_traversalOrder;
|
||||
// calculate.
|
||||
var tempVisited = this.visited.slice();
|
||||
var tempEdge = [];
|
||||
|
||||
var oldLength = 0;
|
||||
|
||||
while (oldLength < tempVisited.length)
|
||||
{
|
||||
oldLength = tempVisited.length;
|
||||
for (var i = 0; i < tempVisited.length; i++)
|
||||
{
|
||||
if (this.bfs(tempVisited[i], tempVisited, tempEdge))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Format message
|
||||
for (var i = 0; i < tempVisited.length; i ++)
|
||||
{
|
||||
tempVisited[i].upText = (i + 1) + "";
|
||||
message = message + tempVisited[i].mainText + " ";
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
BFSAlgorithm.prototype.getPriority = function()
|
||||
{
|
||||
return -9.5;
|
||||
}
|
||||
|
||||
BFSAlgorithm.prototype.step = function()
|
||||
{
|
||||
for (var i = 0; i < this.visited.length; i++)
|
||||
{
|
||||
if (this.bfs(this.visited[i], this.visited, this.edges))
|
||||
{
|
||||
this.app.redrawGraph();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
return;
|
||||
}
|
||||
|
||||
BFSAlgorithm.prototype.bfs = function(vertex, vertexArray, edgeArray)
|
||||
{
|
||||
for (var i = 0; i < this.graph.vertices.length; i ++)
|
||||
{
|
||||
var nextVertex = this.graph.vertices[i];
|
||||
var edge = this.graph.FindEdgeAny(vertex.id, nextVertex.id);
|
||||
if (edge && !vertexArray.includes(nextVertex))
|
||||
{
|
||||
edgeArray.push(edge);
|
||||
vertexArray.push(nextVertex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Algorithm support multi graph
|
||||
BFSAlgorithm.prototype.IsSupportMultiGraph = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateBFSAlgorithm(graph, app)
|
||||
{
|
||||
return new BFSAlgorithm(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateBFSAlgorithm);
|
||||
386
script/features/algorithms/model/plugins/Coloring.js
Normal file
386
script/features/algorithms/model/plugins/Coloring.js
Normal file
@@ -0,0 +1,386 @@
|
||||
/**
|
||||
* Default handler.
|
||||
* Select using mouse, drag.
|
||||
*
|
||||
*/
|
||||
function Coloring(graph, app)
|
||||
{
|
||||
BaseAlgorithm.apply(this, arguments);
|
||||
this.connectedComponentNumber = 0;
|
||||
this.component = {};
|
||||
this.selectedObjects = [];
|
||||
this.MaxColor = 1000;
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
Coloring.prototype = Object.create(BaseAlgorithm.prototype);
|
||||
|
||||
|
||||
Coloring.prototype.getName = function(local)
|
||||
{
|
||||
return g_ColoringName; //local == "ru" ? "Раскраска графа" : "Graph coloring";
|
||||
}
|
||||
|
||||
Coloring.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.GraphColoring";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
Coloring.prototype.getMessage = function(local)
|
||||
{
|
||||
return g_colorNumber + " " + this.connectedComponentNumber;
|
||||
}
|
||||
|
||||
Coloring.prototype.result = function(resultCallback)
|
||||
{
|
||||
this.calculate(true);
|
||||
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
this.selectedObjects = this.component;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Coloring.prototype.calculate = function(fillUpText = false)
|
||||
{
|
||||
this.connectedComponentNumber = 0;
|
||||
this.component = {};
|
||||
connectedVertex = getVertexToVertexArray(this.graph, true);
|
||||
|
||||
var listOfOrders = [];
|
||||
this.addSimpleAndRandomOrders(listOfOrders);
|
||||
this.addBasedOnDegree(listOfOrders, connectedVertex);
|
||||
this.addForTree(listOfOrders, connectedVertex);
|
||||
|
||||
this.connectedComponentNumber = this.MaxColor;
|
||||
|
||||
// Find minimal variant.
|
||||
for (var i = 0; i < listOfOrders.length; i++)
|
||||
{
|
||||
var coloringComponent = this.makeColoring(listOfOrders[i], connectedVertex);
|
||||
if (coloringComponent["max"] < this.connectedComponentNumber)
|
||||
{
|
||||
this.component = coloringComponent;
|
||||
this.connectedComponentNumber = coloringComponent["max"];
|
||||
}
|
||||
}
|
||||
|
||||
// Fill Up text
|
||||
for (var i = 0; i < this.graph.vertices.length; i++)
|
||||
{
|
||||
this.graph.vertices[i].upText = this.component[this.graph.vertices[i].id];
|
||||
}
|
||||
|
||||
//var result = {};
|
||||
//result["version"] = 1;
|
||||
//this.selectedObjects = this.component;
|
||||
|
||||
return this.connectedComponentNumber;
|
||||
}
|
||||
|
||||
Coloring.prototype.makeColoring = function(vertexOrder, connectedVertex)
|
||||
{
|
||||
var res = {};
|
||||
var maxColor = 0;
|
||||
|
||||
for (var i = 0; i < vertexOrder.length; i++)
|
||||
{
|
||||
var id = this.graph.vertices[vertexOrder[i]].id;
|
||||
var hasColor = {};
|
||||
if (id in connectedVertex)
|
||||
{
|
||||
// find color of neighbors.
|
||||
for (var j = 0; j < connectedVertex[id].length; j++)
|
||||
{
|
||||
nearId = connectedVertex[id][j].id;
|
||||
if (nearId in res)
|
||||
{
|
||||
hasColor[res[nearId]] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find color for current vertex;
|
||||
var color = 0;
|
||||
for (var j = 1; j < this.MaxColor; j++)
|
||||
{
|
||||
if (!(j in hasColor))
|
||||
{
|
||||
color = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
res[id] = color;
|
||||
maxColor = Math.max(maxColor, color);
|
||||
}
|
||||
|
||||
res["max"] = maxColor;
|
||||
return res;
|
||||
}
|
||||
|
||||
Coloring.prototype.addSimpleAndRandomOrders = function(listOfOrders)
|
||||
{
|
||||
var vertexOrder = [];
|
||||
for (var i = 0; i < this.graph.vertices.length; i++)
|
||||
{
|
||||
vertexOrder.push(i);
|
||||
}
|
||||
|
||||
// As in graph
|
||||
listOfOrders.push(vertexOrder);
|
||||
// Push some randoms
|
||||
for (var i = 0; i < Math.floor(Math.sqrt(this.graph.vertices.length)); i++)
|
||||
{
|
||||
listOfOrders.push(this.shuffleArray(vertexOrder));
|
||||
}
|
||||
}
|
||||
|
||||
Coloring.prototype.addBasedOnDegree = function(listOfOrders, connectedVertex)
|
||||
{
|
||||
var vertexDegree = [];
|
||||
for (var i = 0; i < this.graph.vertices.length; i++)
|
||||
{
|
||||
var degree = 0;
|
||||
var id = this.graph.vertices[i].id;
|
||||
if (id in connectedVertex)
|
||||
{
|
||||
degree = connectedVertex[id].length;
|
||||
}
|
||||
|
||||
vertexDegree.push({index : i, degree : degree});
|
||||
}
|
||||
|
||||
// sort
|
||||
vertexDegree.sort(
|
||||
function(a, b) {
|
||||
return (a.degree > b.degree) ? -1 :
|
||||
((b.degree > a.degree) ? 1 : 0);
|
||||
});
|
||||
|
||||
var vertexOrder = [];
|
||||
for (var i = 0; i < vertexDegree.length; i++)
|
||||
{
|
||||
vertexOrder.push(vertexDegree[i].index);
|
||||
}
|
||||
|
||||
//console.log(vertexDegree);
|
||||
|
||||
// Sorted by degree.
|
||||
listOfOrders.push(vertexOrder);
|
||||
|
||||
var shuffleLitle = vertexOrder.slice();
|
||||
for (var i = 0; i < shuffleLitle.length - 1; i +=2)
|
||||
{
|
||||
var t = shuffleLitle[i];
|
||||
shuffleLitle[i] = shuffleLitle[i + 1];
|
||||
shuffleLitle[i + 1] = t;
|
||||
}
|
||||
|
||||
// Swap near.
|
||||
listOfOrders.push(shuffleLitle);
|
||||
|
||||
// shufl by half
|
||||
if (vertexDegree.length > 1)
|
||||
{
|
||||
var pivotElement = Math.round(vertexOrder.length / 2);
|
||||
var randomByPart = this.shuffleArray(vertexOrder.slice(0, pivotElement)).concat(this.shuffleArray(vertexOrder.slice(pivotElement)));
|
||||
listOfOrders.push(randomByPart);
|
||||
|
||||
// add with random pivots
|
||||
for (var i = 0; i < Math.floor(Math.sqrt(this.graph.vertices.length)); i++)
|
||||
{
|
||||
var pivot = Math.floor(Math.random() * (vertexOrder.length - 2)) + 1;
|
||||
|
||||
var randomByPart = this.shuffleArray(vertexOrder.slice(0, pivot)).concat(this.shuffleArray(vertexOrder.slice(pivot)));
|
||||
listOfOrders.push(randomByPart);
|
||||
//console.log(randomByPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Coloring.prototype.addForTree = function(listOfOrders, connectedVertex)
|
||||
{
|
||||
var vertexDegree = [];
|
||||
var idToIndex = {};
|
||||
var idToDegree = {};
|
||||
for (var i = 0; i < this.graph.vertices.length; i++)
|
||||
{
|
||||
var degree = 0;
|
||||
var id = this.graph.vertices[i].id;
|
||||
if (id in connectedVertex)
|
||||
{
|
||||
degree = connectedVertex[id].length;
|
||||
}
|
||||
|
||||
vertexDegree.push({index : i, degree : degree});
|
||||
idToIndex[id] = i;
|
||||
idToDegree[id] = degree;
|
||||
}
|
||||
|
||||
// sort
|
||||
vertexDegree.sort(
|
||||
function(a, b) {
|
||||
return (a.degree > b.degree) ? -1 :
|
||||
((b.degree > a.degree) ? 1 : 0);
|
||||
});
|
||||
|
||||
var vertexDegreeOrder = [];
|
||||
for (var i = 0; i < vertexDegree.length; i++)
|
||||
{
|
||||
vertexDegreeOrder.push(vertexDegree[i].index);
|
||||
}
|
||||
|
||||
{
|
||||
var wasAdded = {};
|
||||
var resSimple = [];
|
||||
|
||||
//------ simple near ------
|
||||
for (var i = 0; i < vertexDegreeOrder.length; i++)
|
||||
{
|
||||
var vertex = this.graph.vertices[vertexDegreeOrder[i]].id;
|
||||
if (!(vertex in wasAdded))
|
||||
{
|
||||
wasAdded[vertex] = 1;
|
||||
resSimple.push(idToIndex[vertex]);
|
||||
|
||||
var queue = [];
|
||||
queue.push(vertex);
|
||||
|
||||
while (true)
|
||||
{
|
||||
var needBreak = true;
|
||||
for (var j = 0; j < queue.length; j++)
|
||||
{
|
||||
var vertexId = queue[j];
|
||||
if (vertexId in connectedVertex)
|
||||
{
|
||||
for (var k = 0; k < connectedVertex[vertexId].length; k++)
|
||||
{
|
||||
if (!(connectedVertex[vertexId][k].id in wasAdded))
|
||||
{
|
||||
var id = connectedVertex[vertexId][k].id;
|
||||
wasAdded[id] = 1;
|
||||
queue.push(id);
|
||||
resSimple.push(idToIndex[id]);
|
||||
needBreak = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needBreak)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
listOfOrders.push(resSimple);
|
||||
}
|
||||
//-------------------------------
|
||||
|
||||
|
||||
//------ simple near with max degree
|
||||
{
|
||||
var wasAdded = {};
|
||||
var resMaxDegree = [];
|
||||
for (var i = 0; i < vertexDegreeOrder.length; i++)
|
||||
{
|
||||
var vertex = this.graph.vertices[vertexDegreeOrder[i]].id;
|
||||
if (!(vertex in wasAdded))
|
||||
{
|
||||
wasAdded[vertex] = 1;
|
||||
resMaxDegree.push(idToIndex[vertex]);
|
||||
|
||||
var queue = [];
|
||||
queue.push(vertex);
|
||||
|
||||
while (true)
|
||||
{
|
||||
var needBreak = true;
|
||||
for (var j = 0; j < queue.length; j++)
|
||||
{
|
||||
var vertexId = queue[j];
|
||||
if (vertexId in connectedVertex)
|
||||
{
|
||||
var maxDegree = -1;
|
||||
var vertexMaxId = -1;
|
||||
|
||||
for (var k = 0; k < connectedVertex[vertexId].length; k++)
|
||||
{
|
||||
if (!(connectedVertex[vertexId][k].id in wasAdded))
|
||||
{
|
||||
var id = connectedVertex[vertexId][k].id;
|
||||
|
||||
if (idToDegree[id] > maxDegree)
|
||||
{
|
||||
maxDegree = idToDegree[id];
|
||||
vertexMaxId = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vertexMaxId >= 0)
|
||||
{
|
||||
wasAdded[vertexMaxId] = 1;
|
||||
queue.push(vertexMaxId);
|
||||
resMaxDegree.push(idToIndex[vertexMaxId]);
|
||||
needBreak = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needBreak)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
listOfOrders.push(resMaxDegree);
|
||||
}
|
||||
//-------------------------------
|
||||
}
|
||||
|
||||
Coloring.prototype.shuffleArray = function(a)
|
||||
{
|
||||
var j, x, i;
|
||||
for (i = a.length - 1; i > 0; i--) {
|
||||
j = Math.floor(Math.random() * (i + 1));
|
||||
x = a[i];
|
||||
a[i] = a[j];
|
||||
a[j] = x;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
Coloring.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
|
||||
}
|
||||
|
||||
Coloring.prototype.getPriority = function()
|
||||
{
|
||||
return -9.0;
|
||||
}
|
||||
|
||||
// Algorithm support multi graph
|
||||
Coloring.prototype.IsSupportMultiGraph = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateColoring(graph, app)
|
||||
{
|
||||
return new Coloring(graph)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateColoring);
|
||||
130
script/features/algorithms/model/plugins/ConnectedComponent.js
Normal file
130
script/features/algorithms/model/plugins/ConnectedComponent.js
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Default handler.
|
||||
* Select using mouse, drag.
|
||||
*
|
||||
*/
|
||||
function FindConnectedComponentNew(graph, app)
|
||||
{
|
||||
BaseAlgorithm.apply(this, arguments);
|
||||
this.connectedComponentNumber = 0;
|
||||
this.component = {};
|
||||
this.selectedObjects = [];
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
FindConnectedComponentNew.prototype = Object.create(BaseAlgorithm.prototype);
|
||||
|
||||
|
||||
FindConnectedComponentNew.prototype.getName = function(local)
|
||||
{
|
||||
return g_findConnectedComponent; //local == "ru" ? "Найти компоненты связности" : "Find connected components";
|
||||
}
|
||||
|
||||
FindConnectedComponentNew.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.ConnectedComponent";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
FindConnectedComponentNew.prototype.getMessage = function(local)
|
||||
{
|
||||
return (this.graph.hasDirectEdge() ? g_sickConnectedComponent : g_connectedComponent) + this.connectedComponentNumber;
|
||||
}
|
||||
|
||||
FindConnectedComponentNew.prototype.result = function(resultCallback)
|
||||
{
|
||||
this.calculate(true);
|
||||
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
this.selectedObjects = this.component;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
FindConnectedComponentNew.prototype.calculate = function(fillUpText = false)
|
||||
{
|
||||
this.connectedComponentNumber = 0;
|
||||
this.component = {};
|
||||
var tempVertices = this.graph.vertices.slice();
|
||||
connectedVertex = getVertexToVertexArray(this.graph, true);
|
||||
var connectedComponentNumber = 0;
|
||||
|
||||
while (tempVertices.length > 0)
|
||||
{
|
||||
connectedComponentNumber++;
|
||||
|
||||
var stack = [];
|
||||
stack.push(tempVertices[0]);
|
||||
|
||||
tempVertices.splice(0, 1);
|
||||
|
||||
indexInStack = 0;
|
||||
|
||||
for (i = 0; i < stack.length; i++)
|
||||
{
|
||||
var stackElement = stack[i];
|
||||
this.component[stackElement.id] = connectedComponentNumber;
|
||||
if (fillUpText)
|
||||
{
|
||||
stackElement.upText = connectedComponentNumber;
|
||||
}
|
||||
|
||||
if (connectedVertex.hasOwnProperty(stackElement.id))
|
||||
{
|
||||
for (j = 0; j < connectedVertex[stackElement.id].length; j++)
|
||||
{
|
||||
var nextVertex = connectedVertex[stackElement.id][j];
|
||||
var connectedEdge = this.graph.FindEdgeAny(stackElement.id, nextVertex.id);
|
||||
if (stack.indexOf(nextVertex) < 0)
|
||||
{
|
||||
stack.push(nextVertex);
|
||||
tempVertices.splice(tempVertices.indexOf(nextVertex), 1);
|
||||
if (connectedEdge)
|
||||
{
|
||||
this.component[connectedEdge.id] = connectedComponentNumber;
|
||||
}
|
||||
}
|
||||
else if (connectedEdge && !(connectedEdge.id in this.component))
|
||||
{
|
||||
this.component[connectedEdge.id] = connectedComponentNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.connectedComponentNumber = connectedComponentNumber;
|
||||
|
||||
//var result = {};
|
||||
//result["version"] = 1;
|
||||
//this.selectedObjects = this.component;
|
||||
|
||||
return this.connectedComponentNumber;
|
||||
}
|
||||
|
||||
FindConnectedComponentNew.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
|
||||
}
|
||||
|
||||
FindConnectedComponentNew.prototype.getPriority = function()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Algorithm support multi graph
|
||||
FindConnectedComponentNew.prototype.IsSupportMultiGraph = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateConnectedComponetsNew(graph, app)
|
||||
{
|
||||
return new FindConnectedComponentNew(graph)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateConnectedComponetsNew);
|
||||
124
script/features/algorithms/model/plugins/DFS.js
Normal file
124
script/features/algorithms/model/plugins/DFS.js
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Find short path.
|
||||
*
|
||||
*/
|
||||
function DFSAlgorithm(graph, app)
|
||||
{
|
||||
BaseTraversal.apply(this, arguments);
|
||||
this.message = g_startTraversal;
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
DFSAlgorithm.prototype = Object.create(BaseTraversal.prototype);
|
||||
// timer interval
|
||||
DFSAlgorithm.prototype.timerInterval = 500;
|
||||
|
||||
DFSAlgorithm.prototype.getName = function(local)
|
||||
{
|
||||
return g_DFSName;// local == "ru" ? "Поиск в глубину" : "Depth-first search";
|
||||
}
|
||||
|
||||
DFSAlgorithm.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.DFSAlgorithm";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
DFSAlgorithm.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
DFSAlgorithm.prototype.result = function(resultCallback)
|
||||
{
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DFSAlgorithm.prototype.getMainMessage = function()
|
||||
{
|
||||
var message = g_traversalOrder;
|
||||
// calculate.
|
||||
var tempVisited = this.visited.slice();
|
||||
var tempEdge = [];
|
||||
|
||||
var oldLength = 0;
|
||||
|
||||
while (oldLength < tempVisited.length)
|
||||
{
|
||||
oldLength = tempVisited.length;
|
||||
for (var i = tempVisited.length - 1; i >= 0; i--)
|
||||
{
|
||||
if (this.dfs(tempVisited[i], tempVisited, tempEdge))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Format message
|
||||
for (var i = 0; i < tempVisited.length; i ++)
|
||||
{
|
||||
tempVisited[i].upText = (i + 1) + "";
|
||||
message = message + tempVisited[i].mainText + " ";
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
DFSAlgorithm.prototype.getPriority = function()
|
||||
{
|
||||
return -9.5;
|
||||
}
|
||||
|
||||
DFSAlgorithm.prototype.getCategory = function()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
DFSAlgorithm.prototype.step = function()
|
||||
{
|
||||
for (var i = this.visited.length - 1; i >= 0; i--)
|
||||
{
|
||||
if (this.dfs(this.visited[i], this.visited, this.edges))
|
||||
{
|
||||
this.app.redrawGraph();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
return;
|
||||
}
|
||||
|
||||
DFSAlgorithm.prototype.dfs = function(vertex, vertexArray, edgeArray)
|
||||
{
|
||||
for (var i = 0; i < this.graph.vertices.length; i ++)
|
||||
{
|
||||
var nextVertex = this.graph.vertices[i];
|
||||
var edge = this.graph.FindEdgeAny(vertex.id, nextVertex.id);
|
||||
if (edge && !vertexArray.includes(nextVertex))
|
||||
{
|
||||
edgeArray.push(edge);
|
||||
vertexArray.push(nextVertex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Algorithm support multi graph
|
||||
DFSAlgorithm.prototype.IsSupportMultiGraph = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateDFSAlgorithm(graph, app)
|
||||
{
|
||||
return new DFSAlgorithm(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateDFSAlgorithm);
|
||||
97
script/features/algorithms/model/plugins/EulerianLoop.js
Normal file
97
script/features/algorithms/model/plugins/EulerianLoop.js
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Find Eulerian Loop.
|
||||
*
|
||||
*/
|
||||
function FindEulerianLoop(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
this.message = g_processing;
|
||||
this.selectedObjects = [];
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
FindEulerianLoop.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
|
||||
|
||||
FindEulerianLoop.prototype.getName = function(local)
|
||||
{
|
||||
return g_EulerinLoopName;//local == "ru" ? "Найти Эйлеров цикл" : "Find Eulerian cycle";
|
||||
}
|
||||
|
||||
FindEulerianLoop.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.FindEulerianCycle";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
FindEulerianLoop.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
FindEulerianLoop.prototype.getCategory = function()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
FindEulerianLoop.prototype.result = function(resultCallback)
|
||||
{
|
||||
this.outResultCallback = function (result ) { resultCallback(result); };
|
||||
self = this;
|
||||
this.CalculateAlgorithm("elloop", [], function (pathObjects, properties, results)
|
||||
{
|
||||
self.resultCallback(pathObjects, properties, results);
|
||||
}, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FindEulerianLoop.prototype.resultCallback = function(pathObjects, properties, results)
|
||||
{
|
||||
result = results.length > 0 && results[0].value > 0 && results[0].type == 1;
|
||||
|
||||
var outputResult = {};
|
||||
outputResult["version"] = 1;
|
||||
|
||||
this.message = result > 0 ? g_hasEulerianLoop : g_hasNotEulerianLoop;
|
||||
if (result > 0)
|
||||
{
|
||||
var nodesPath = this.GetNodesPath(results, 1, results.length - 1);
|
||||
outputResult["paths"] = [];
|
||||
outputResult["paths"].push(nodesPath);
|
||||
this.selectedObjects = [];
|
||||
|
||||
for (var i = 0; i < pathObjects.length; i++)
|
||||
{
|
||||
this.selectedObjects[pathObjects[i].id] = 1;
|
||||
}
|
||||
|
||||
this.message = this.message + ": ";
|
||||
for (var i = 0; i < nodesPath.length; i++)
|
||||
{
|
||||
this.message = this.message + this.graph.FindVertex(nodesPath[i]).mainText + ((i < nodesPath.length - 1) ? "⇒" : "");
|
||||
}
|
||||
}
|
||||
|
||||
this.outResultCallback(outputResult);
|
||||
}
|
||||
|
||||
FindEulerianLoop.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
|
||||
}
|
||||
|
||||
FindEulerianLoop.prototype.getPriority = function()
|
||||
{
|
||||
return -7.5;
|
||||
}
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateFindEulerianLoop(graph, app)
|
||||
{
|
||||
return new FindEulerianLoop(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateFindEulerianLoop);
|
||||
97
script/features/algorithms/model/plugins/EulerianPath.js
Normal file
97
script/features/algorithms/model/plugins/EulerianPath.js
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Find Eulerian Path.
|
||||
*
|
||||
*/
|
||||
function FindEulerianPath(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
this.message = g_processing;
|
||||
this.selectedObjects = [];
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
FindEulerianPath.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
|
||||
|
||||
FindEulerianPath.prototype.getName = function(local)
|
||||
{
|
||||
return g_EulerinPath;//local == "ru" ? "Найти Эйлерову цепь" : "Find Eulerian path";
|
||||
}
|
||||
|
||||
FindEulerianPath.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.FindEulerianPath";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
FindEulerianPath.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
FindEulerianPath.prototype.getCategory = function()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
FindEulerianPath.prototype.result = function(resultCallback)
|
||||
{
|
||||
this.outResultCallback = function (result ) { resultCallback(result); };
|
||||
self = this;
|
||||
this.CalculateAlgorithm("elpath", [], function (pathObjects, properties, results)
|
||||
{
|
||||
self.resultCallback(pathObjects, properties, results);
|
||||
}, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FindEulerianPath.prototype.resultCallback = function(pathObjects, properties, results)
|
||||
{
|
||||
result = results.length > 0 && results[0].value > 0 && results[0].type == 1;
|
||||
|
||||
var outputResult = {};
|
||||
outputResult["version"] = 1;
|
||||
|
||||
this.message = result > 0 ? g_hasEulerianPath : g_hasNotEulerianPath;
|
||||
if (result > 0)
|
||||
{
|
||||
var nodesPath = this.GetNodesPath(results, 1, results.length - 1);
|
||||
outputResult["paths"] = [];
|
||||
outputResult["paths"].push(nodesPath);
|
||||
this.selectedObjects = [];
|
||||
|
||||
for (var i = 0; i < pathObjects.length; i++)
|
||||
{
|
||||
this.selectedObjects[pathObjects[i].id] = 1;
|
||||
}
|
||||
|
||||
this.message = this.message + ": ";
|
||||
for (var i = 0; i < nodesPath.length; i++)
|
||||
{
|
||||
this.message = this.message + this.graph.FindVertex(nodesPath[i]).mainText + ((i < nodesPath.length - 1) ? "⇒" : "");
|
||||
}
|
||||
}
|
||||
|
||||
this.outResultCallback(outputResult);
|
||||
}
|
||||
|
||||
FindEulerianPath.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
|
||||
}
|
||||
|
||||
FindEulerianPath.prototype.getPriority = function()
|
||||
{
|
||||
return -7.5;
|
||||
}
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateFindEulerianPath(graph, app)
|
||||
{
|
||||
return new FindEulerianPath(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateFindEulerianPath);
|
||||
232
script/features/algorithms/model/plugins/FindAllPatches.js
Normal file
232
script/features/algorithms/model/plugins/FindAllPatches.js
Normal file
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
* Find short path.
|
||||
*
|
||||
*/
|
||||
function FindAllPathes(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
this.message = g_selectStartVertex;
|
||||
this.selectedObjects = {};
|
||||
this.foundSubGraphs = {};
|
||||
this.nSubgraphIndex = 0;
|
||||
this.nSubGraphCount = 0;
|
||||
this.foundPaths = {};
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
FindAllPathes.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
// First selected.
|
||||
FindAllPathes.prototype.firstObject = null;
|
||||
// Second selected.
|
||||
FindAllPathes.prototype.secondObject = null;
|
||||
// Path
|
||||
FindAllPathes.prototype.pathObjects = null;
|
||||
// Infinity
|
||||
FindAllPathes.prototype.infinityValue = 1E9 - 1;
|
||||
|
||||
FindAllPathes.prototype.getName = function(local)
|
||||
{
|
||||
return g_findAllPathes;
|
||||
}
|
||||
|
||||
FindAllPathes.prototype.getId = function()
|
||||
{
|
||||
return "Abin.FindAllPathes";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
FindAllPathes.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
FindAllPathes.prototype.getCategory = function()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
FindAllPathes.prototype.result = function(resultCallback)
|
||||
{
|
||||
if (this.firstObject && this.secondObject)
|
||||
{
|
||||
this.outResultCallback = function (result ) { resultCallback(result); };
|
||||
self = this;
|
||||
this.CalculateAlgorithm("prnpaths", [
|
||||
{name: "start", value: this.firstObject.id},
|
||||
{name: "finish", value: this.secondObject.id}
|
||||
],
|
||||
function (pathObjects, properties, results)
|
||||
{
|
||||
self.resultCallback(pathObjects, properties, results);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
FindAllPathes.prototype.setResultMessage = function()
|
||||
{
|
||||
if (this.nSubGraphCount > 0)
|
||||
{
|
||||
var currentPath = "";
|
||||
var first = true;
|
||||
this.foundPaths[this.nSubgraphIndex].forEach((nodeId) => {
|
||||
currentPath += (first ? "" : "⇒") + this.graph.FindVertex(nodeId).mainText;
|
||||
first = false;
|
||||
});
|
||||
|
||||
this.message = g_numberOfPathesFrom + this.firstObject.mainText +
|
||||
g_to + this.secondObject.mainText + g_are +
|
||||
this.nSubGraphCount + ". " + g_pathN + (1 + parseInt(this.nSubgraphIndex)) + ": " + currentPath +
|
||||
" <select style=\"float:right\" id=\"enumSubgraphs\"></select>";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.message = g_pathNotExists;
|
||||
}
|
||||
}
|
||||
|
||||
FindAllPathes.prototype.resultCallback = function(pathObjects, properties, results)
|
||||
{
|
||||
var outputResult = {};
|
||||
outputResult["version"] = 1;
|
||||
outputResult["minPath"] = true;
|
||||
|
||||
this.pathObjects = pathObjects;
|
||||
this.properties = properties;
|
||||
|
||||
var bFound = results.length > 0 && results[0].value < this.infinityValue && (results[0].type == 1 || results[0].type == 2);
|
||||
|
||||
if (bFound)
|
||||
{
|
||||
this.nSubGraphCount = results.length > 0 && results[0].type == 1 ? results[0].value : 0;
|
||||
|
||||
this.foundSubGraphs = {};
|
||||
this.foundPaths = {};
|
||||
for (var i = 0; i < this.nSubGraphCount; i++)
|
||||
{
|
||||
this.foundSubGraphs[i] = {};
|
||||
this.foundPaths[i] = [];
|
||||
}
|
||||
|
||||
var subGraphIndex = 0;
|
||||
var prevNodeId = -1;
|
||||
for (var i = 0; i < results.length; i++)
|
||||
{
|
||||
if (results[i].type == 6)
|
||||
{
|
||||
subGraphIndex++;
|
||||
prevNodeId = -1;
|
||||
}
|
||||
|
||||
if (results[i].type == 4)
|
||||
{
|
||||
var nodeId = parseInt(results[i].value);
|
||||
var index = subGraphIndex;
|
||||
var subgGraph = this.foundSubGraphs[index];
|
||||
subgGraph[nodeId] = true;
|
||||
|
||||
this.foundPaths[index].push(nodeId);
|
||||
|
||||
if (prevNodeId >= 0)
|
||||
{
|
||||
var edgeObject = this.graph.FindEdgeMin(prevNodeId, nodeId);
|
||||
subgGraph[edgeObject.id] = true;
|
||||
}
|
||||
prevNodeId = nodeId;
|
||||
}
|
||||
}
|
||||
|
||||
this.setResultMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.secondObject = null;
|
||||
this.firstObject = null;
|
||||
this.message = g_pathNotExists;
|
||||
}
|
||||
|
||||
this.outResultCallback(outputResult);
|
||||
}
|
||||
|
||||
FindAllPathes.prototype.messageWasChanged = function()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
if ($('#enumSubgraphs'))
|
||||
{
|
||||
for (var i = 0; i < this.nSubGraphCount; i++)
|
||||
{
|
||||
$('#enumSubgraphs').append("<option value=\"" + i + "\"" + (self.nSubgraphIndex==i ? "selected": "") + ">" +
|
||||
g_pathN + (i + 1) +
|
||||
"</option>");
|
||||
}
|
||||
|
||||
$('#enumSubgraphs').change(function () {
|
||||
self.nSubgraphIndex = $('#enumSubgraphs').val();
|
||||
self.setResultMessage();
|
||||
self.app.redrawGraph();
|
||||
self.app.updateMessage();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
FindAllPathes.prototype.selectVertex = function(vertex)
|
||||
{
|
||||
this.pathObjects = null;
|
||||
this.shortDist = null;
|
||||
|
||||
if (this.firstObject)
|
||||
{
|
||||
this.message = g_processing;
|
||||
this.secondObject = vertex;
|
||||
this.selectedObjects = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
this.firstObject = vertex;
|
||||
this.secondObject = null;
|
||||
this.selectedObjects = {};
|
||||
this.message = g_selectFinishVertex;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FindAllPathes.prototype.deselectAll = function()
|
||||
{
|
||||
this.firstObject = null;
|
||||
this.secondObject = null;
|
||||
this.selectedObjects = {};
|
||||
this.foundSubGraphs = {};
|
||||
this.nSubgraphIndex = 0;
|
||||
this.nSubGraphCount = 0;
|
||||
this.message = g_selectStartVertex;
|
||||
return true;
|
||||
}
|
||||
|
||||
FindAllPathes.prototype.instance = function()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FindAllPathes.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (this.nSubgraphIndex in this.foundSubGraphs && object.id in this.foundSubGraphs[this.nSubgraphIndex]) ? 1 :
|
||||
(object.id in this.selectedObjects) ? this.selectedObjects[object.id] : ((object == this.firstObject || object == object.secondObject) ? 1 : 0);
|
||||
}
|
||||
|
||||
FindAllPathes.prototype.getPriority = function()
|
||||
{
|
||||
return -9.4;
|
||||
}
|
||||
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateFindAllPathes(graph, app)
|
||||
{
|
||||
return new FindAllPathes(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateFindAllPathes);
|
||||
229
script/features/algorithms/model/plugins/FindLongestPath.js
Normal file
229
script/features/algorithms/model/plugins/FindLongestPath.js
Normal file
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* Find short path.
|
||||
*
|
||||
*/
|
||||
function FindLongestPath(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
this.message = g_selectStartVertex;
|
||||
this.selectedObjects = {};
|
||||
this.foundSubGraphs = {};
|
||||
this.nSubgraphIndex = 0;
|
||||
this.nSubGraphCount = 0;
|
||||
this.foundPaths = {};
|
||||
this.maxPathLength = 0;
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
FindLongestPath.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
// First selected.
|
||||
FindLongestPath.prototype.firstObject = null;
|
||||
// Second selected.
|
||||
FindLongestPath.prototype.secondObject = null;
|
||||
// Path
|
||||
FindLongestPath.prototype.pathObjects = null;
|
||||
// Infinity
|
||||
FindLongestPath.prototype.infinityValue = 1E9 - 1;
|
||||
|
||||
FindLongestPath.prototype.getName = function(local)
|
||||
{
|
||||
return g_findLongestPath;
|
||||
}
|
||||
|
||||
FindLongestPath.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.FindLongestPath";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
FindLongestPath.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
FindLongestPath.prototype.getCategory = function()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
FindLongestPath.prototype.result = function(resultCallback)
|
||||
{
|
||||
if (this.firstObject && this.secondObject)
|
||||
{
|
||||
this.outResultCallback = function (result ) { resultCallback(result); };
|
||||
self = this;
|
||||
this.CalculateAlgorithm("prnpaths", [
|
||||
{name: "start", value: this.firstObject.id},
|
||||
{name: "finish", value: this.secondObject.id}
|
||||
],
|
||||
function (pathObjects, properties, results)
|
||||
{
|
||||
self.resultCallback(pathObjects, properties, results);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
FindLongestPath.prototype.setResultMessage = function()
|
||||
{
|
||||
if (this.nSubGraphCount > 0)
|
||||
{
|
||||
var currentPath = "";
|
||||
var first = true;
|
||||
this.foundPaths[this.nSubgraphIndex].forEach((nodeId) => {
|
||||
currentPath += (first ? "" : "⇒") + this.graph.FindVertex(nodeId).mainText;
|
||||
first = false;
|
||||
});
|
||||
|
||||
this.message = g_LengthOfLongestPathFrom + this.firstObject.mainText +
|
||||
g_to + this.secondObject.mainText + g_are +
|
||||
this.maxPathLength + ": " + currentPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.message = g_pathNotExists;
|
||||
}
|
||||
}
|
||||
|
||||
FindLongestPath.prototype.resultCallback = function(pathObjects, properties, results)
|
||||
{
|
||||
var outputResult = {};
|
||||
outputResult["version"] = 1;
|
||||
outputResult["minPath"] = true;
|
||||
|
||||
this.pathObjects = pathObjects;
|
||||
this.properties = properties;
|
||||
|
||||
var bFound = results.length > 0 && results[0].value < this.infinityValue && (results[0].type == 1 || results[0].type == 2);
|
||||
|
||||
if (bFound)
|
||||
{
|
||||
this.nSubGraphCount = results.length > 0 && results[0].type == 1 ? results[0].value : 0;
|
||||
|
||||
this.foundSubGraphs = {};
|
||||
this.foundPaths = {};
|
||||
this.maxPathLength = 0;
|
||||
var maxPathIndex = 0;
|
||||
var currentLength = 0;
|
||||
for (var i = 0; i < this.nSubGraphCount; i++)
|
||||
{
|
||||
this.foundSubGraphs[i] = {};
|
||||
this.foundPaths[i] = [];
|
||||
}
|
||||
|
||||
var subGraphIndex = 0;
|
||||
var prevNodeId = -1;
|
||||
for (var i = 0; i < results.length; i++)
|
||||
{
|
||||
if (results[i].type == 6)
|
||||
{
|
||||
if (currentLength > this.maxPathLength) {
|
||||
this.maxPathLength = currentLength;
|
||||
maxPathIndex = subGraphIndex;
|
||||
}
|
||||
currentLength = 0;
|
||||
subGraphIndex++;
|
||||
prevNodeId = -1;
|
||||
}
|
||||
|
||||
if (results[i].type == 4)
|
||||
{
|
||||
var nodeId = parseInt(results[i].value);
|
||||
var index = subGraphIndex;
|
||||
var subgGraph = this.foundSubGraphs[index];
|
||||
subgGraph[nodeId] = true;
|
||||
|
||||
this.foundPaths[index].push(nodeId);
|
||||
|
||||
if (prevNodeId >= 0)
|
||||
{
|
||||
var edgeObject = this.graph.FindEdgeMax(prevNodeId, nodeId);
|
||||
subgGraph[edgeObject.id] = true;
|
||||
currentLength += edgeObject.GetWeight();
|
||||
}
|
||||
prevNodeId = nodeId;
|
||||
}
|
||||
}
|
||||
if (currentLength > this.maxPathLength) {
|
||||
this.maxPathLength = currentLength;
|
||||
maxPathIndex = subGraphIndex;
|
||||
}
|
||||
this.nSubgraphIndex = maxPathIndex;
|
||||
|
||||
this.setResultMessage();
|
||||
|
||||
this.firstObject = null;
|
||||
this.secondObject = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.secondObject = null;
|
||||
this.firstObject = null;
|
||||
this.message = g_pathNotExists;
|
||||
}
|
||||
|
||||
this.outResultCallback(outputResult);
|
||||
}
|
||||
|
||||
FindLongestPath.prototype.selectVertex = function(vertex)
|
||||
{
|
||||
this.pathObjects = null;
|
||||
this.shortDist = null;
|
||||
|
||||
if (this.firstObject)
|
||||
{
|
||||
this.message = g_processing;
|
||||
this.secondObject = vertex;
|
||||
this.selectedObjects = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
this.deselectAll();
|
||||
this.firstObject = vertex;
|
||||
this.secondObject = null;
|
||||
this.selectedObjects = {};
|
||||
this.message = g_selectFinishVertex;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FindLongestPath.prototype.deselectAll = function()
|
||||
{
|
||||
this.firstObject = null;
|
||||
this.secondObject = null;
|
||||
this.selectedObjects = {};
|
||||
this.foundSubGraphs = {};
|
||||
this.nSubgraphIndex = 0;
|
||||
this.nSubGraphCount = 0;
|
||||
this.message = g_selectStartVertex;
|
||||
this.maxPathLength = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
FindLongestPath.prototype.instance = function()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FindLongestPath.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (this.nSubgraphIndex in this.foundSubGraphs && object.id in this.foundSubGraphs[this.nSubgraphIndex]) ? 1 :
|
||||
(object.id in this.selectedObjects) ? this.selectedObjects[object.id] : ((object == this.firstObject || object == object.secondObject) ? 1 : 0);
|
||||
}
|
||||
|
||||
FindLongestPath.prototype.getPriority = function()
|
||||
{
|
||||
return -9.4;
|
||||
}
|
||||
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateFindLongestPath(graph, app)
|
||||
{
|
||||
return new FindLongestPath(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateFindLongestPath);
|
||||
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* Find short path.
|
||||
*
|
||||
*/
|
||||
function FindShortPatchsFromOne(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
this.message = g_selectStartVertex;
|
||||
this.selectedObjects = {};
|
||||
this.foundSubGraphs = {};
|
||||
this.nSubgraphIndex = 0;
|
||||
this.nSubGraphCount = 0;
|
||||
this.lastVertexInPath = [];
|
||||
this.lengthOfPath = [];
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
FindShortPatchsFromOne.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
// First selected.
|
||||
FindShortPatchsFromOne.prototype.firstObject = null;
|
||||
// Path
|
||||
FindShortPatchsFromOne.prototype.pathObjects = null;
|
||||
// Infinity
|
||||
FindShortPatchsFromOne.prototype.infinityValue = 1E9 - 1;
|
||||
|
||||
FindShortPatchsFromOne.prototype.getName = function(local)
|
||||
{
|
||||
return g_findAllPathesFromVertex;
|
||||
}
|
||||
|
||||
FindShortPatchsFromOne.prototype.getId = function()
|
||||
{
|
||||
return "Abin.FindShortPatchsFromOne";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
FindShortPatchsFromOne.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
FindShortPatchsFromOne.prototype.getCategory = function()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
FindShortPatchsFromOne.prototype.result = function(resultCallback)
|
||||
{
|
||||
if (this.firstObject)
|
||||
{
|
||||
this.outResultCallback = function (result ) { resultCallback(result); };
|
||||
self = this;
|
||||
this.CalculateAlgorithm("blf", [
|
||||
{name: "start", value : this.firstObject.id}
|
||||
], function (pathObjects, properties, results)
|
||||
{
|
||||
self.resultCallback(pathObjects, properties, results);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
FindShortPatchsFromOne.prototype.setResultMessage = function()
|
||||
{
|
||||
if (this.nSubGraphCount > 0)
|
||||
{
|
||||
this.message = g_distanceFrom + this.firstObject.mainText +
|
||||
g_to + this.lastVertexInPath[this.nSubgraphIndex] + g_are +
|
||||
this.lengthOfPath[this.nSubgraphIndex] + " <select style=\"float:right\" id=\"enumSubgraphs\"></select>";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.message = g_pathNotExists;
|
||||
}
|
||||
}
|
||||
|
||||
FindShortPatchsFromOne.prototype.resultCallback = function(pathObjects, properties, results)
|
||||
{
|
||||
var outputResult = {};
|
||||
outputResult["version"] = 1;
|
||||
outputResult["minPath"] = true;
|
||||
|
||||
this.pathObjects = pathObjects;
|
||||
this.properties = properties;
|
||||
|
||||
var bFound = results.length > 0 && results[0].value < this.infinityValue && (results[0].type == 1 || results[0].type == 2);
|
||||
|
||||
if (bFound)
|
||||
{
|
||||
this.nSubGraphCount = results.length > 0 && results[0].type == 1 ? results[0].value : 0;
|
||||
|
||||
this.foundSubGraphs = {};
|
||||
for (var i = 0; i < this.nSubGraphCount; i++)
|
||||
{
|
||||
this.foundSubGraphs[i] = {};
|
||||
this.lengthOfPath.push(0);
|
||||
this.lastVertexInPath.push(0);
|
||||
}
|
||||
|
||||
var subGraphIndex = 0;
|
||||
var prevNodeId = -1;
|
||||
for (var i = 0; i < results.length; i++)
|
||||
{
|
||||
if (results[i].type == 6)
|
||||
{
|
||||
subGraphIndex++;
|
||||
prevNodeId = -1;
|
||||
}
|
||||
|
||||
if (results[i].type == 4)
|
||||
{
|
||||
var nodeId = parseInt(results[i].value);
|
||||
var index = subGraphIndex;
|
||||
var subgGraph = this.foundSubGraphs[index];
|
||||
subgGraph[nodeId] = true;
|
||||
var vertex = this.graph.FindVertex(nodeId);
|
||||
this.lastVertexInPath[index] = vertex != null ? vertex.mainText : "";
|
||||
|
||||
if (prevNodeId >= 0)
|
||||
{
|
||||
var edgeObject = this.graph.FindEdgeMin(prevNodeId, nodeId);
|
||||
subgGraph[edgeObject.id] = true;
|
||||
this.lengthOfPath[index] += edgeObject.GetWeight();
|
||||
}
|
||||
prevNodeId = nodeId;
|
||||
}
|
||||
}
|
||||
|
||||
this.setResultMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.firstObject = null;
|
||||
this.message = g_pathNotExists;
|
||||
}
|
||||
|
||||
this.outResultCallback(outputResult);
|
||||
}
|
||||
|
||||
FindShortPatchsFromOne.prototype.messageWasChanged = function()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
if ($('#enumSubgraphs'))
|
||||
{
|
||||
for (var i = 0; i < this.nSubGraphCount; i++)
|
||||
{
|
||||
$('#enumSubgraphs').append("<option value=\"" + i + "\"" + (self.nSubgraphIndex==i ? "selected": "") + ">" +
|
||||
g_pathTo + this.lastVertexInPath[i] +
|
||||
"</option>");
|
||||
}
|
||||
|
||||
$('#enumSubgraphs').change(function () {
|
||||
self.nSubgraphIndex = $('#enumSubgraphs').val();
|
||||
self.app.redrawGraph();
|
||||
self.setResultMessage();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
FindShortPatchsFromOne.prototype.selectVertex = function(vertex)
|
||||
{
|
||||
this.pathObjects = null;
|
||||
this.shortDist = null;
|
||||
|
||||
this.deselectAll();
|
||||
|
||||
this.firstObject = vertex;
|
||||
this.selectedObjects = {};
|
||||
this.message = "Processing...";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FindShortPatchsFromOne.prototype.deselectAll = function()
|
||||
{
|
||||
this.firstObject = null;
|
||||
this.selectedObjects = {};
|
||||
this.foundSubGraphs = {};
|
||||
this.nSubgraphIndex = 0;
|
||||
this.nSubGraphCount = 0;
|
||||
this.message = g_selectStartVertex;
|
||||
this.lastVertexInPath = [];
|
||||
this.lengthOfPath = [];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FindShortPatchsFromOne.prototype.instance = function()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FindShortPatchsFromOne.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (this.nSubgraphIndex in this.foundSubGraphs && object.id in this.foundSubGraphs[this.nSubgraphIndex]) ? 1 :
|
||||
(object.id in this.selectedObjects) ? this.selectedObjects[object.id] : ((object == this.firstObject || object == object.secondObject) ? 1 : 0);
|
||||
}
|
||||
|
||||
FindShortPatchsFromOne.prototype.getPriority = function()
|
||||
{
|
||||
return -9.4;
|
||||
}
|
||||
|
||||
// Algorithm support multi graph
|
||||
FindShortPatchsFromOne.prototype.IsSupportMultiGraph = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateFindShortPatchsFromOne(graph, app)
|
||||
{
|
||||
return new FindShortPatchsFromOne(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateFindShortPatchsFromOne);
|
||||
235
script/features/algorithms/model/plugins/Floid.js
Normal file
235
script/features/algorithms/model/plugins/Floid.js
Normal file
@@ -0,0 +1,235 @@
|
||||
/**
|
||||
* Find short path.
|
||||
*
|
||||
*/
|
||||
function FloidAlgorithm(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
this.selectedObjects = {};
|
||||
this.matrix = [];
|
||||
this.updateMessage(false);
|
||||
this.edgesCopy = [];
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
FloidAlgorithm.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
// First selected.
|
||||
FloidAlgorithm.prototype.firstObject = null;
|
||||
// Second selected.
|
||||
FloidAlgorithm.prototype.secondObject = null;
|
||||
// Path
|
||||
FloidAlgorithm.prototype.pathObjects = null;
|
||||
// infinity
|
||||
FloidAlgorithm.prototype.infinity = 1E8;
|
||||
|
||||
FloidAlgorithm.prototype.getName = function(local)
|
||||
{
|
||||
return g_FloidName; //local == "ru" ? "Алгоритм Флойда — Уоршелла" : "Floyd–Warshall algorithm";
|
||||
}
|
||||
|
||||
FloidAlgorithm.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.FloidAlgorithm";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
FloidAlgorithm.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
FloidAlgorithm.prototype.getCategory = function()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
FloidAlgorithm.prototype.result = function(resultCallback)
|
||||
{
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
|
||||
this.matrix = [];
|
||||
|
||||
this.resultMatrix();
|
||||
|
||||
//console.log(this.matrix);
|
||||
|
||||
// Remove all edges.
|
||||
this.egdesCopy = this.graph.edges.slice();
|
||||
this.removeAllEdges();
|
||||
this.isGraphMulti = this.graph.isMulti();
|
||||
|
||||
this.graph.hasDirect = false;
|
||||
|
||||
// Added new edges
|
||||
for (var i = 0; i < this.graph.vertices.length; i ++)
|
||||
{
|
||||
for (var j = 0; j < this.graph.vertices.length; j ++)
|
||||
{
|
||||
if (i != j)
|
||||
{
|
||||
var directed = (this.matrix[i][j] != this.matrix[j][i]);
|
||||
if (this.matrix[i][j] < this.infinity && (directed || i < j))
|
||||
{
|
||||
this.graph.AddNewEdgeSafe(this.graph.vertices[i], this.graph.vertices[j], directed, this.matrix[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.app.redrawGraph();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
FloidAlgorithm.prototype.resultMatrix = function()
|
||||
{
|
||||
this.matrix = [];
|
||||
|
||||
for (var i = 0; i < this.graph.vertices.length; i ++)
|
||||
{
|
||||
this.matrix.push([]);
|
||||
var v1 = this.graph.vertices[i];
|
||||
var str = "";
|
||||
for (var j = 0; j < this.graph.vertices.length; j ++)
|
||||
{
|
||||
var v2 = this.graph.vertices[j];
|
||||
var edge = this.graph.FindEdgeMin(v1.id, v2.id);
|
||||
if (edge != null)
|
||||
{
|
||||
this.matrix[i][j] = edge.GetWeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.matrix[i][j] = this.infinity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var k = 0; k < this.graph.vertices.length; k ++)
|
||||
for (var i = 0; i < this.graph.vertices.length; i ++)
|
||||
for (var j = 0; j < this.graph.vertices.length; j ++)
|
||||
{
|
||||
if (this.matrix[i][j] > this.matrix[i][k] + this.matrix[k][j])
|
||||
{
|
||||
this.matrix[i][j] = this.matrix[i][k] + this.matrix[k][j];
|
||||
}
|
||||
}
|
||||
|
||||
return this.matrix;
|
||||
}
|
||||
|
||||
|
||||
FloidAlgorithm.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
FloidAlgorithm.prototype.messageWasChanged = function()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
var matrixButton = document.getElementById("showFloidMatrix");
|
||||
if (matrixButton)
|
||||
{
|
||||
matrixButton.onclick = function () {
|
||||
var dialogButtons = {};
|
||||
dialogButtons[g_close] = function() {
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
$( "#FloidMatrixField" ).val(self.GetFloidMatrix());
|
||||
$( "#floidMatrix" ).dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: "auto",
|
||||
modal: true,
|
||||
title: g_minDistMatrixText,
|
||||
buttons: dialogButtons,
|
||||
dialogClass: 'EdgeDialog'
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
$('#saveFloidGraph').change(function() {
|
||||
self.updateMessage(this.checked);
|
||||
});
|
||||
}
|
||||
|
||||
FloidAlgorithm.prototype.GetFloidMatrix = function()
|
||||
{
|
||||
return this.graph.GetAdjacencyMatrixStr();
|
||||
}
|
||||
|
||||
|
||||
FloidAlgorithm.prototype.changedType = function()
|
||||
{
|
||||
var enumReport = document.getElementById("enumReport");
|
||||
|
||||
this.app.SetCurrentValue("findShortPathReportType", enumReport.options[enumReport.selectedIndex].value);
|
||||
this.updateUpText();
|
||||
}
|
||||
|
||||
FloidAlgorithm.prototype.getPriority = function()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
FloidAlgorithm.prototype.removeAllEdges = function()
|
||||
{
|
||||
while (this.graph.edges.length > 0)
|
||||
{
|
||||
this.graph.DeleteEdge(this.graph.edges[0]);
|
||||
}
|
||||
}
|
||||
|
||||
FloidAlgorithm.prototype.wantRestore = function()
|
||||
{
|
||||
console.log($("#saveFloidGraph").is(':checked'));
|
||||
return !$("#saveFloidGraph").is(':checked');
|
||||
}
|
||||
|
||||
FloidAlgorithm.prototype.restore = function()
|
||||
{
|
||||
this.removeAllEdges();
|
||||
|
||||
this.graph.hasDirect = false;
|
||||
console.log(this.egdesCopy);
|
||||
|
||||
for (var i = 0; i < this.egdesCopy.length; i ++)
|
||||
{
|
||||
var edgeIndex = this.graph.AddNewEdgeSafe(this.egdesCopy[i].vertex1,
|
||||
this.egdesCopy[i].vertex2,
|
||||
this.egdesCopy[i].isDirect,
|
||||
this.egdesCopy[i].weight,
|
||||
this.isGraphMulti);
|
||||
|
||||
var edge = this.graph.edges[edgeIndex];
|
||||
edge.model.type = this.egdesCopy[i].model.type;
|
||||
edge.model.curveValue = this.egdesCopy[i].model.curveValue;
|
||||
|
||||
//edge.model = this.egdesCopy[i].model;
|
||||
}
|
||||
}
|
||||
|
||||
FloidAlgorithm.prototype.updateMessage = function(save)
|
||||
{
|
||||
this.message = g_graphOfMinDist + " <label style=\"margin-bottom: 0px\">" + g_checkToSave + " <input id=\"saveFloidGraph\" type=\"checkbox\"" + (save ? "checked" : "") + "></label>" +
|
||||
"<button type=\"button\" class=\"btn btn-default btn-xs\" id=\"showFloidMatrix\" style=\"float:right\">" + g_showDistMatrix + "</button>"
|
||||
}
|
||||
|
||||
// Algorithm support multi graph
|
||||
FloidAlgorithm.prototype.IsSupportMultiGraph = function ()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateFloidAlgorithm(graph, app)
|
||||
{
|
||||
return new FloidAlgorithm(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateFloidAlgorithm);
|
||||
175
script/features/algorithms/model/plugins/GraphReorder.js
Normal file
175
script/features/algorithms/model/plugins/GraphReorder.js
Normal file
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
* Algorithm for reorder graph.
|
||||
*
|
||||
*/
|
||||
function GraphReorder(graph, app)
|
||||
{
|
||||
BaseAlgorithm.apply(this, arguments);
|
||||
if (graph != null)
|
||||
{
|
||||
this.edges = graph.edges;
|
||||
this.vertices = graph.vertices;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
GraphReorder.prototype = Object.create(BaseAlgorithm.prototype);
|
||||
|
||||
|
||||
GraphReorder.prototype.getName = function(local)
|
||||
{
|
||||
return g_GraphReorder; //local == "ru" ? "Упорядочить граф" : "Arrange the graph";
|
||||
}
|
||||
|
||||
GraphReorder.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.GraphReorder";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
GraphReorder.prototype.getMessage = function(local)
|
||||
{
|
||||
return g_done;
|
||||
}
|
||||
|
||||
GraphReorder.prototype.result = function(resultCallback)
|
||||
{
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
|
||||
if (this.vertices.length == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var velocityDamping = 0.85;
|
||||
var diameter = (new VertexModel()).diameter;
|
||||
var maxDistance = diameter * 3;
|
||||
var gravityDistanceSqr = 10 * (maxDistance * maxDistance);
|
||||
var edgeGravityKof = 10 / (maxDistance);
|
||||
var kCenterForce = 10 / (maxDistance * 10);
|
||||
//var centerPoint = viewportSize.multiply(0.5);
|
||||
var velocityMax = maxDistance * 10;
|
||||
|
||||
var centerPoint = new Point();
|
||||
for(i = 0; i < this.vertices.length; i++) // loop through vertices
|
||||
{
|
||||
centerPoint.add(this.vertices[i].position);
|
||||
}
|
||||
centerPoint.multiply(1.0 / this.vertices.length);
|
||||
|
||||
var edgesMatrix = {};
|
||||
for (var i = 0; i < this.edges.length; i++)
|
||||
{
|
||||
edgesMatrix[this.edges[i].vertex1.id + this.edges[i].vertex2.id * 1000] = 1;
|
||||
edgesMatrix[this.edges[i].vertex2.id + this.edges[i].vertex1.id * 1000] = 1;
|
||||
}
|
||||
|
||||
var k = 0;
|
||||
var bChanged = true;
|
||||
while (k < 1000 && bChanged)
|
||||
{
|
||||
var vertexData = [];
|
||||
for(i = 0; i < this.vertices.length; i++) // loop through vertices
|
||||
{
|
||||
// Has no in newVertices.
|
||||
var currentVertex = {};
|
||||
currentVertex.object = this.vertices[i];
|
||||
currentVertex.net_force = new Point (0, 0);
|
||||
currentVertex.velocity = new Point (0, 0);
|
||||
vertexData.push(currentVertex);
|
||||
|
||||
for(j = 0; j < this.vertices.length; j++) // loop through other vertices
|
||||
{
|
||||
otherVertex = this.vertices[j];
|
||||
|
||||
if (otherVertex == currentVertex.object) continue;
|
||||
|
||||
// squared distance between "u" and "v" in 2D space
|
||||
var rsq = currentVertex.object.position.distanceSqr(otherVertex.position);
|
||||
|
||||
{
|
||||
// counting the repulsion between two vertices
|
||||
var force = (currentVertex.object.position.subtract(otherVertex.position)).normalize(gravityDistanceSqr / rsq);
|
||||
currentVertex.net_force = currentVertex.net_force.add(force);
|
||||
}
|
||||
}
|
||||
|
||||
for(j = 0; j < this.vertices.length; j++) // loop through edges
|
||||
{
|
||||
otherVertex = this.vertices[j];
|
||||
if (edgesMatrix.hasOwnProperty(currentVertex.object.id + 1000 * otherVertex.id))
|
||||
{
|
||||
var distance = currentVertex.object.position.distance(otherVertex.position);
|
||||
|
||||
if (distance > maxDistance)
|
||||
{
|
||||
// countin the attraction
|
||||
var force = (otherVertex.position.subtract(currentVertex.object.position)).normalize(edgeGravityKof * (distance - maxDistance));
|
||||
currentVertex.net_force = currentVertex.net_force.add(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate force to center of world.
|
||||
var distanceToCenter = centerPoint.distance(currentVertex.object.position);
|
||||
var force = centerPoint.subtract(currentVertex.object.position).normalize(distanceToCenter * kCenterForce);
|
||||
currentVertex.net_force = currentVertex.net_force.add(force);
|
||||
|
||||
// counting the velocity (with damping 0.85)
|
||||
currentVertex.velocity = currentVertex.velocity.add(currentVertex.net_force);
|
||||
}
|
||||
|
||||
bChanged = false;
|
||||
|
||||
for(i = 0; i < vertexData.length; i++) // set new positions
|
||||
{
|
||||
var v = vertexData[i];
|
||||
var velocity = v.velocity;
|
||||
if (velocity.length() > velocityMax)
|
||||
{
|
||||
velocity = velocity.normalize(velocityMax);
|
||||
}
|
||||
v.object.position = v.object.position.add(velocity);
|
||||
if (velocity.length() >= 1)
|
||||
{
|
||||
bChanged = true;
|
||||
}
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
||||
|
||||
this.app.OnAutoAdjustViewport();
|
||||
this.app.SetHandlerMode("default");
|
||||
// Looks like somthing going wrong and will use circle algorithm for reposition.
|
||||
//var bbox = this.getGraphBBox();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GraphReorder.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
GraphReorder.prototype.getPriority = function()
|
||||
{
|
||||
return -8.5;
|
||||
}
|
||||
|
||||
// Algorithm support multi graph
|
||||
GraphReorder.prototype.IsSupportMultiGraph = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateAlgorithmGraphReorder(graph, app)
|
||||
{
|
||||
return new GraphReorder(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateAlgorithmGraphReorder);
|
||||
114
script/features/algorithms/model/plugins/HamiltonianLoop.js
Normal file
114
script/features/algorithms/model/plugins/HamiltonianLoop.js
Normal file
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Find Eulerian Loop.
|
||||
*
|
||||
*/
|
||||
function FindHamiltonianLoop(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
this.message = g_processing;
|
||||
this.selectedObjects = [];
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
FindHamiltonianLoop.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
|
||||
|
||||
FindHamiltonianLoop.prototype.getName = function(local)
|
||||
{
|
||||
return g_HamiltoianCycleName; //local == "ru" ? "Найти Гамильтонов цикл" : "Find Hamiltonian cycle";
|
||||
}
|
||||
|
||||
FindHamiltonianLoop.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.FindHamiltonianLoop";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
FindHamiltonianLoop.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
FindHamiltonianLoop.prototype.getCategory = function()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
FindHamiltonianLoop.prototype.result = function(resultCallback)
|
||||
{
|
||||
this.outResultCallback = function (result ) { resultCallback(result); };
|
||||
self = this;
|
||||
this.CalculateAlgorithm("hamloop", [], function (pathObjects, properties, results)
|
||||
{
|
||||
self.resultCallback(pathObjects, properties, results);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FindHamiltonianLoop.prototype.resultCallback = function(pathObjects, properties, results)
|
||||
{
|
||||
result = results.length > 0 && results[0].value > 0 && results[0].type == 1;
|
||||
|
||||
var outputResult = {};
|
||||
outputResult["version"] = 1;
|
||||
|
||||
this.message = result > 0 ? g_hasHamiltonianLoop : g_hasNotHamiltonianLoop;
|
||||
if (result > 0)
|
||||
{
|
||||
var nodesEdgesPath = this.GetNodesEdgesPath(results, 1, results.length - 1);
|
||||
var nodesPath = this.GetNodesPath(results, 1, results.length - 1);
|
||||
|
||||
this.message = this.message + ": ";
|
||||
|
||||
if (this.graph.isMulti())
|
||||
{
|
||||
outputResult["pathsWithEdges"] = [];
|
||||
outputResult["pathsWithEdges"].push(nodesEdgesPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
outputResult["paths"] = [];
|
||||
outputResult["paths"].push(nodesEdgesPath);
|
||||
}
|
||||
|
||||
for (var i = 0; i < nodesPath.length; i++)
|
||||
{
|
||||
this.message = this.message + this.graph.FindVertex(nodesPath[i]).mainText + ((i < nodesPath.length - 1) ? "⇒" : "");
|
||||
}
|
||||
this.selectedObjects = [];
|
||||
|
||||
for (var i = 0; i < pathObjects.length; i++)
|
||||
{
|
||||
this.selectedObjects[pathObjects[i].id] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
this.outResultCallback(outputResult);
|
||||
}
|
||||
|
||||
FindHamiltonianLoop.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
|
||||
}
|
||||
|
||||
FindHamiltonianLoop.prototype.getPriority = function()
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
// Algorithm support multi graph
|
||||
FindHamiltonianLoop.prototype.IsSupportMultiGraph = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateFindHamiltonianLoop(graph, app)
|
||||
{
|
||||
return new FindHamiltonianLoop(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateFindHamiltonianLoop);
|
||||
112
script/features/algorithms/model/plugins/HamiltonianPath.js
Normal file
112
script/features/algorithms/model/plugins/HamiltonianPath.js
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Find Eulerian Loop.
|
||||
*
|
||||
*/
|
||||
function FindHamiltonianPath(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
this.message = g_processing;
|
||||
this.selectedObjects = [];
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
FindHamiltonianPath.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
|
||||
|
||||
FindHamiltonianPath.prototype.getName = function(local)
|
||||
{
|
||||
return g_HamiltonianPath;//local == "ru" ? "Найти Гамильтонову цепь" : "Find Hamiltonian path";
|
||||
}
|
||||
|
||||
FindHamiltonianPath.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.FindHamiltonianPath";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
FindHamiltonianPath.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
FindHamiltonianPath.prototype.getCategory = function()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
FindHamiltonianPath.prototype.result = function(resultCallback)
|
||||
{
|
||||
this.outResultCallback = function (result ) { resultCallback(result); };
|
||||
self = this;
|
||||
this.CalculateAlgorithm("hampath", [], function (pathObjects, properties, results)
|
||||
{
|
||||
self.resultCallback(pathObjects, properties, results);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FindHamiltonianPath.prototype.resultCallback = function(pathObjects, properties, results)
|
||||
{
|
||||
result = results.length > 0 && results[0].value > 0 && results[0].type == 1;
|
||||
|
||||
var outputResult = {};
|
||||
outputResult["version"] = 1;
|
||||
|
||||
this.message = result > 0 ? g_hasHamiltonianPath : g_hasNotHamiltonianPath;
|
||||
if (result > 0)
|
||||
{
|
||||
var nodesEdgesPath = this.GetNodesEdgesPath(results, 1, results.length - 1);
|
||||
var nodesPath = this.GetNodesPath(results, 1, results.length - 1);
|
||||
|
||||
if (this.graph.isMulti())
|
||||
{
|
||||
outputResult["pathsWithEdges"] = [];
|
||||
outputResult["pathsWithEdges"].push(nodesEdgesPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
outputResult["paths"] = [];
|
||||
outputResult["paths"].push(nodesEdgesPath);
|
||||
}
|
||||
this.selectedObjects = [];
|
||||
|
||||
for (var i = 0; i < pathObjects.length; i++)
|
||||
{
|
||||
this.selectedObjects[pathObjects[i].id] = 1;
|
||||
}
|
||||
|
||||
this.message = this.message + ": ";
|
||||
for (var i = 0; i < nodesPath.length; i++)
|
||||
{
|
||||
this.message = this.message + this.graph.FindVertex(nodesPath[i]).mainText + ((i < nodesPath.length - 1) ? "⇒" : "");
|
||||
}
|
||||
}
|
||||
|
||||
this.outResultCallback(outputResult);
|
||||
}
|
||||
|
||||
FindHamiltonianPath.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
|
||||
}
|
||||
|
||||
FindHamiltonianPath.prototype.getPriority = function()
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
FindHamiltonianPath.prototype.IsSupportMultiGraph = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateFindHamiltonianPath(graph, app)
|
||||
{
|
||||
return new FindHamiltonianPath(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateFindHamiltonianPath);
|
||||
299
script/features/algorithms/model/plugins/IsomorphismCheck.js
Normal file
299
script/features/algorithms/model/plugins/IsomorphismCheck.js
Normal file
@@ -0,0 +1,299 @@
|
||||
/**
|
||||
* Find short path.
|
||||
*
|
||||
*/
|
||||
|
||||
function IsomorphismCheck(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
|
||||
if (graph && app)
|
||||
{
|
||||
this.connectedComponent = new FindConnectedComponentNew(graph, app);
|
||||
this.connectedComponent.calculate();
|
||||
}
|
||||
|
||||
this.setFirstMessage();
|
||||
this.prevCalculated = false;
|
||||
this.searchSubGraphs = false;
|
||||
this.foundSubGraphs = {};
|
||||
this.nSubgraphIndex = 0;
|
||||
this.nSubGraphCount = 0;
|
||||
this.bIsomorph = false;
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
IsomorphismCheck.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
// First selected.
|
||||
IsomorphismCheck.prototype.firstGraph = null;
|
||||
// Second selected.
|
||||
IsomorphismCheck.prototype.secondGraph = null;
|
||||
|
||||
|
||||
IsomorphismCheck.prototype.getName = function(local)
|
||||
{
|
||||
return g_IsomorphismCheck;
|
||||
}
|
||||
|
||||
IsomorphismCheck.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.IsomorphismCheck";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
IsomorphismCheck.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
IsomorphismCheck.prototype.result = function(resultCallback)
|
||||
{
|
||||
if (this.firstGraph && this.secondGraph)
|
||||
{
|
||||
this.outResultCallback = function (result ) { resultCallback(result); };
|
||||
self = this;
|
||||
var params = [
|
||||
{name : "graph1", value: this.getGraphEdges(this.firstGraph)},
|
||||
{name : "graph2", value: this.getGraphEdges(this.secondGraph)},
|
||||
];
|
||||
if (this.searchSubGraphs) {
|
||||
params.push({name: "searchSubgraphs", value: true});
|
||||
}
|
||||
this.CalculateAlgorithm("isocheck", params, function (pathObjects, properties, results)
|
||||
{
|
||||
self.resultCallback(pathObjects, properties, results);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
IsomorphismCheck.prototype.getGraphEdges = function(nodesAndEdges)
|
||||
{
|
||||
var res = ""
|
||||
for (var key in nodesAndEdges)
|
||||
{
|
||||
var edgeObject = this.graph.FindEdgeById(key);
|
||||
if (edgeObject)
|
||||
{
|
||||
if (res != "")
|
||||
res = res + ","
|
||||
res = res + edgeObject.vertex1.id + "-" + edgeObject.vertex2.id;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
IsomorphismCheck.prototype.resultCallback = function(pathObjects, properties, results)
|
||||
{
|
||||
var outputResult = {};
|
||||
outputResult["version"] = 1;
|
||||
|
||||
if (!this.searchSubGraphs)
|
||||
{
|
||||
this.bIsomorph = results.length > 0 && results[0].type == 1 && results[0].value == 1;
|
||||
|
||||
this.setResultMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.nSubGraphCount = results.length > 0 && results[0].type == 1 ? results[0].value : 0;
|
||||
|
||||
this.setResultMessage();
|
||||
|
||||
this.foundSubGraphs = {};
|
||||
for (var i = 0; i < this.nSubGraphCount; i++)
|
||||
{
|
||||
this.foundSubGraphs[i] = {};
|
||||
}
|
||||
|
||||
var subGraphIndex = 0;
|
||||
for (var i = 0; i < results.length; i++)
|
||||
{
|
||||
if (results[i].type == 6)
|
||||
{
|
||||
subGraphIndex++;
|
||||
}
|
||||
|
||||
if (results[i].type == 5)
|
||||
{
|
||||
var edgeId = parseInt(results[i].value);
|
||||
var index = subGraphIndex;
|
||||
var subgGraph = this.foundSubGraphs[index];
|
||||
subgGraph[edgeId] = true;
|
||||
var edgeObject = this.graph.FindEdgeById(edgeId);
|
||||
subgGraph[edgeObject.vertex1.id] = true;
|
||||
subgGraph[edgeObject.vertex2.id] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.prevCalculated = true;
|
||||
this.outResultCallback(outputResult);
|
||||
}
|
||||
|
||||
IsomorphismCheck.prototype.selectVertex = function(vertex)
|
||||
{
|
||||
if (this.connectedComponent && this.connectedComponent.connectedComponentNumber <= 1)
|
||||
return true;
|
||||
|
||||
if (this.firstGraph && !this.prevCalculated && (!this.firstGraph || !(vertex.id in this.firstGraph)))
|
||||
{
|
||||
this.message = g_processing;
|
||||
this.secondGraph = this.getGraphWithNode(vertex);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.deselectAll();
|
||||
|
||||
this.firstGraph = this.getGraphWithNode(vertex);
|
||||
this.secondGraph = null;
|
||||
this.setSecondMessage();
|
||||
this.app.updateMessage();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IsomorphismCheck.prototype.deselectAll = function()
|
||||
{
|
||||
this.firstGraph = null;
|
||||
this.secondGraph = null;
|
||||
this.prevCalculated = false;
|
||||
this.setFirstMessage();
|
||||
this.restore();
|
||||
this.foundSubGraphs = {};
|
||||
this.nSubgraphIndex = 0;
|
||||
this.nSubGraphCount = 0;
|
||||
this.bIsomorph = false;
|
||||
|
||||
this.app.updateMessage();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IsomorphismCheck.prototype.instance = function()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IsomorphismCheck.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (this.nSubgraphIndex in this.foundSubGraphs && object.id in this.foundSubGraphs[this.nSubgraphIndex]) ? 3 :
|
||||
(this.firstGraph && object.id in this.firstGraph) ? 1 : ((this.secondGraph && object.id in this.secondGraph) ? 2 : 0);
|
||||
}
|
||||
|
||||
IsomorphismCheck.prototype.getPriority = function()
|
||||
{
|
||||
return -8.0;
|
||||
}
|
||||
|
||||
IsomorphismCheck.prototype.getGraphWithNode = function(node)
|
||||
{
|
||||
var res = {}
|
||||
if (node.id in this.connectedComponent.component)
|
||||
{
|
||||
var componentNumber = this.connectedComponent.component[node.id];
|
||||
for (var key in this.connectedComponent.component)
|
||||
{
|
||||
if (this.connectedComponent.component[key] == componentNumber)
|
||||
{
|
||||
res[key] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
IsomorphismCheck.prototype.setFirstMessage = function()
|
||||
{
|
||||
if (this.connectedComponent && this.connectedComponent.connectedComponentNumber <= 1)
|
||||
{
|
||||
this.message = g_graphHasNoAtleast2Graphs;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.searchSubGraphs)
|
||||
this.message = g_selectFirstGraphIsomorphismCheck + "<input id=\"searchSubGraph\" type=\"checkbox\" " + (this.searchSubGraphs ? "checked": "")+ " style=\"float:right\">" + "<label style=\"margin-bottom: 0px;float:right\">" + g_searchIsomorphSubgraph + " </label>";
|
||||
else
|
||||
this.message = g_selectFirstGraphPatternCheck + "<input id=\"searchSubGraph\" type=\"checkbox\" " + (this.searchSubGraphs ? "checked": "")+ " style=\"float:right\">" + "<label style=\"margin-bottom: 0px;float:right\">" + g_searchIsomorphSubgraph + " </label>";
|
||||
}
|
||||
|
||||
IsomorphismCheck.prototype.setSecondMessage = function()
|
||||
{
|
||||
if (!this.searchSubGraphs)
|
||||
this.message = g_selectSecondGraphIsomorphismCheck + "<input id=\"searchSubGraph\" type=\"checkbox\" " + (this.searchSubGraphs ? "checked": "")+ " style=\"float:right\">" + "<label style=\"margin-bottom: 0px;float:right\">" + g_searchIsomorphSubgraph + " </label>";
|
||||
else
|
||||
this.message = g_selectSecondGraphForSearchSubgraph + "<input id=\"searchSubGraph\" type=\"checkbox\" " + (this.searchSubGraphs ? "checked": "")+ " style=\"float:right\">" + "<label style=\"margin-bottom: 0px;float:right\">" + g_searchIsomorphSubgraph + " </label>";
|
||||
}
|
||||
|
||||
IsomorphismCheck.prototype.setResultMessage = function()
|
||||
{
|
||||
if (!this.searchSubGraphs)
|
||||
{
|
||||
if (this.bIsomorph)
|
||||
{
|
||||
this.message = g_graphsIsomorph;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.message = g_graphsNotIsomorph;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.nSubGraphCount > 0)
|
||||
{
|
||||
this.message = g_numberOfIsomorphSubgraphIs + this.nSubGraphCount + " <select style=\"float:right\" id=\"enumSubgraphs\"></select>";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.message = g_graphHasNoIsomorphSubgraph;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IsomorphismCheck.prototype.messageWasChanged = function()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
if ($('#searchSubGraph'))
|
||||
{
|
||||
$('#searchSubGraph').change(function() {
|
||||
self.searchSubGraphs = this.checked;
|
||||
if (self.firstGraph && !self.prevCalculated)
|
||||
self.setSecondMessage();
|
||||
else
|
||||
self.setFirstMessage();
|
||||
|
||||
self.app.updateMessage();
|
||||
});
|
||||
}
|
||||
|
||||
if ($('#enumSubgraphs'))
|
||||
{
|
||||
for (var i = 0; i < this.nSubGraphCount; i++)
|
||||
{
|
||||
$('#enumSubgraphs').append("<option value=\"" + i + "\"" + (self.nSubgraphIndex==i ? "selected": "") + ">" +
|
||||
g_subgraphNo + (i + 1) +
|
||||
"</option>");
|
||||
}
|
||||
|
||||
$('#enumSubgraphs').change(function () {
|
||||
self.nSubgraphIndex = $('#enumSubgraphs').val();
|
||||
self.app.redrawGraph();
|
||||
self.setResultMessage();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateIsomorphismCheck(graph, app)
|
||||
{
|
||||
return new IsomorphismCheck(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateIsomorphismCheck);
|
||||
100
script/features/algorithms/model/plugins/MaxClique.js
Normal file
100
script/features/algorithms/model/plugins/MaxClique.js
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Find Eulerian Loop.
|
||||
*
|
||||
*/
|
||||
function MaxClique(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
this.message = g_processing;
|
||||
this.selectedObjects = [];
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
MaxClique.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
|
||||
|
||||
MaxClique.prototype.getName = function(local)
|
||||
{
|
||||
return g_MaxClique;
|
||||
}
|
||||
|
||||
MaxClique.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.MaxClique";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
MaxClique.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
MaxClique.prototype.result = function(resultCallback)
|
||||
{
|
||||
this.outResultCallback = function (result ) { resultCallback(result); };
|
||||
self = this;
|
||||
this.CalculateAlgorithm("mc", [], function (pathObjects, properties, results)
|
||||
{
|
||||
self.resultCallback(pathObjects, properties, results);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MaxClique.prototype.resultCallback = function(pathObjects, properties, results)
|
||||
{
|
||||
result = results.length > 0 && results[0].value > 0 && results[0].type == 1;
|
||||
|
||||
var outputResult = {};
|
||||
outputResult["version"] = 1;
|
||||
|
||||
console.log("properties");
|
||||
console.log(properties);
|
||||
console.log("results");
|
||||
console.log(results);
|
||||
console.log("pathObjects");
|
||||
console.log(pathObjects);
|
||||
|
||||
this.message = result > 0 ? "" : g_MaxCliqueNotFound;
|
||||
if (result > 0)
|
||||
{
|
||||
let size = results[0].value;
|
||||
this.message = g_MaxCliqueSizeIs + size;
|
||||
|
||||
this.selectedObjects = [];
|
||||
|
||||
this.message = this.message + g_MaxCliqueContains;
|
||||
|
||||
var vertexIndex = 0;
|
||||
for (var i = 0; i < pathObjects.length; i++)
|
||||
{
|
||||
let object = pathObjects[i];
|
||||
if (object instanceof BaseVertex) {
|
||||
this.message = this.message + object.mainText + ((vertexIndex < size - 1) ? ", " : ".");
|
||||
vertexIndex++;
|
||||
}
|
||||
this.selectedObjects[object.id] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
this.outResultCallback(outputResult);
|
||||
}
|
||||
|
||||
MaxClique.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
|
||||
}
|
||||
|
||||
MaxClique.prototype.getPriority = function()
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
function CreateMaxClique(graph, app)
|
||||
{
|
||||
return new MaxClique(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateMaxClique);
|
||||
227
script/features/algorithms/model/plugins/MaxFlow.js
Normal file
227
script/features/algorithms/model/plugins/MaxFlow.js
Normal file
@@ -0,0 +1,227 @@
|
||||
/**
|
||||
* Find short path.
|
||||
*
|
||||
*/
|
||||
function FindMaxFlow(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
this.message = g_selectStartVertexForMaxFlow;
|
||||
this.selectedObjects = {};
|
||||
this.selectedEdges = [];
|
||||
this.resetUpText = [];
|
||||
|
||||
this.minEdgeSize = 2;
|
||||
this.maxEdgeSize = 12;
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
FindMaxFlow.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
// First selected.
|
||||
FindMaxFlow.prototype.firstObject = null;
|
||||
// Second selected.
|
||||
FindMaxFlow.prototype.secondObject = null;
|
||||
// Path
|
||||
FindMaxFlow.prototype.selectedEdges = null;
|
||||
|
||||
|
||||
FindMaxFlow.prototype.getName = function(local)
|
||||
{
|
||||
return g_MaxFlowName; //local == "ru" ? "Поиск максимального потока" : "Find Maximum flow";
|
||||
}
|
||||
|
||||
FindMaxFlow.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.FindMaxFlow";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
FindMaxFlow.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
FindMaxFlow.prototype.result = function(resultCallback)
|
||||
{
|
||||
if (this.firstObject && this.secondObject)
|
||||
{
|
||||
this.outResultCallback = function (result ) { resultCallback(result); };
|
||||
self = this;
|
||||
this.CalculateAlgorithm("mfpr",
|
||||
[
|
||||
{name: "source", value: this.firstObject.id},
|
||||
{name: "drain", value: this.secondObject.id}
|
||||
],
|
||||
function (pathObjects, properties, results)
|
||||
{
|
||||
self.resultCallback(pathObjects, properties, results);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
FindMaxFlow.prototype.resultCallback = function(pathObjects, properties, results)
|
||||
{
|
||||
var outputResult = {};
|
||||
outputResult["version"] = 1;
|
||||
|
||||
this.pathObjects = pathObjects;
|
||||
this.properties = properties;
|
||||
|
||||
var bFound = results.length > 0 && results[0].value < 1E5 && (results[0].type == 1 || results[0].type == 2) && results[0].value * 1 > 0.0;
|
||||
|
||||
var maxFlow = results[0].value * 1;
|
||||
|
||||
if (bFound)
|
||||
{
|
||||
this.selectedObjects = {};
|
||||
|
||||
var defaultDiameter = (new EdgeModel()).width;
|
||||
|
||||
var avgFlow = 0;
|
||||
var countEdges = 0;
|
||||
|
||||
for (var i = 0; i < pathObjects.length; i++)
|
||||
{
|
||||
if (pathObjects[i] instanceof BaseEdge)
|
||||
{
|
||||
avgFlow += properties[pathObjects[i].id]["flowValue"] * 1;
|
||||
countEdges += 1;
|
||||
}
|
||||
}
|
||||
avgFlow = avgFlow / countEdges;
|
||||
|
||||
for (var i = 0; i < pathObjects.length; i++)
|
||||
{
|
||||
if (pathObjects[i] instanceof BaseEdge)
|
||||
{
|
||||
this.selectedObjects[pathObjects[i].id] = 1;
|
||||
var flow = properties[pathObjects[i].id]["flowValue"] * 1;
|
||||
if (pathObjects[i].useWeight || flow != pathObjects[i].GetWeight())
|
||||
{
|
||||
pathObjects[i].text = flow + " / " + pathObjects[i].GetWeight();
|
||||
}
|
||||
if (!pathObjects[i].isDirect)
|
||||
{
|
||||
if (parseInt(properties[pathObjects[i].id]["backToFront"]) > 0)
|
||||
{
|
||||
pathObjects[i].arrayStyleStart = "arrow";
|
||||
}
|
||||
else
|
||||
{
|
||||
pathObjects[i].arrayStyleFinish = "arrow";
|
||||
}
|
||||
}
|
||||
|
||||
pathObjects[i].model.width = Math.max(Math.min((flow / avgFlow) * defaultDiameter, this.maxEdgeSize), this.minEdgeSize);
|
||||
}
|
||||
}
|
||||
this.selectedEdges = pathObjects;
|
||||
|
||||
this.message = g_maxFlowResult.replace("%1", (maxFlow).toString()).replace("%2", this.firstObject.mainText).replace("%3", this.secondObject.mainText);
|
||||
|
||||
this.selectedObjects[this.secondObject.id] = 3;
|
||||
this.selectedObjects[this.firstObject.id] = 1;
|
||||
|
||||
this.secondObject.upText = g_sinkVertex;
|
||||
this.resetUpText.push(this.secondObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.message = g_flowNotExists.toString().replace("%1", this.firstObject.mainText).replace("%2", this.secondObject.mainText);
|
||||
}
|
||||
this.secondObject = null;
|
||||
this.firstObject = null;
|
||||
|
||||
this.outResultCallback(outputResult);
|
||||
}
|
||||
|
||||
FindMaxFlow.prototype.selectVertex = function(vertex)
|
||||
{
|
||||
this.pathObjects = null;
|
||||
this.shortDist = null;
|
||||
|
||||
if (this.firstObject)
|
||||
{
|
||||
this.message = g_processing;
|
||||
this.secondObject = vertex;
|
||||
this.selectedObjects = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
this.restore();
|
||||
|
||||
this.firstObject = vertex;
|
||||
this.secondObject = null;
|
||||
this.selectedObjects = {};
|
||||
this.message = g_selectFinishVertexForMaxFlow;
|
||||
this.firstObject.upText = g_sourceVertex;
|
||||
this.resetUpText.push(this.firstObject);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FindMaxFlow.prototype.deselectAll = function()
|
||||
{
|
||||
this.firstObject = null;
|
||||
this.secondObject = null;
|
||||
this.selectedObjects = {};
|
||||
this.message = g_selectStartVertexForMaxFlow;
|
||||
this.restore();
|
||||
return true;
|
||||
}
|
||||
|
||||
FindMaxFlow.prototype.instance = function()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FindMaxFlow.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : ((object == this.firstObject || object == object.secondObject) ? 1 : 0);
|
||||
}
|
||||
|
||||
FindMaxFlow.prototype.getPriority = function()
|
||||
{
|
||||
return -8.0;
|
||||
}
|
||||
|
||||
// @return true, if you change resotry graph after use.
|
||||
BaseAlgorithm.prototype.wantRestore = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// calls this method if wantRestore return true.
|
||||
BaseAlgorithm.prototype.restore = function()
|
||||
{
|
||||
if (this.selectedEdges != null)
|
||||
{
|
||||
for (var i = 0; i < this.selectedEdges.length; i++)
|
||||
{
|
||||
if (this.selectedEdges[i] instanceof BaseEdge)
|
||||
{
|
||||
this.selectedEdges[i].text = "";
|
||||
this.selectedEdges[i].arrayStyleStart = "";
|
||||
this.selectedEdges[i].arrayStyleFinish = "";
|
||||
this.selectedEdges[i].model.width = (new EdgeModel()).width;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.resetUpText.length; i++)
|
||||
{
|
||||
this.resetUpText[i].upText = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateFindMaxFlow(graph, app)
|
||||
{
|
||||
return new FindMaxFlow(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateFindMaxFlow);
|
||||
167
script/features/algorithms/model/plugins/MinimumSpanningTree.js
Normal file
167
script/features/algorithms/model/plugins/MinimumSpanningTree.js
Normal file
@@ -0,0 +1,167 @@
|
||||
|
||||
function MinimumSpanningTree(graph, app)
|
||||
{
|
||||
BaseAlgorithm.apply(this, arguments);
|
||||
this.isNotConnected = false;
|
||||
this.MST = 0;
|
||||
this.edges = [];
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
MinimumSpanningTree.prototype = Object.create(BaseAlgorithm.prototype);
|
||||
|
||||
|
||||
MinimumSpanningTree.prototype.getName = function(local)
|
||||
{
|
||||
return g_minimumSpanningTree; //local == "ru" ? "Поиск минимального остовного дерева" : "Search of minimum spanning tree";
|
||||
}
|
||||
|
||||
MinimumSpanningTree.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.minimalSpanningTree";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
MinimumSpanningTree.prototype.getMessage = function(local)
|
||||
{
|
||||
if (!this.isNotConnected )
|
||||
{
|
||||
return g_SpanningTreeResult + this.MST + ". " +
|
||||
(this.graph.hasDirectEdge() ? g_SpanningTreeIgnoreDir : "");
|
||||
}
|
||||
else
|
||||
{
|
||||
return g_SpanningTreeNotConnected;
|
||||
}
|
||||
}
|
||||
|
||||
MinimumSpanningTree.prototype.result = function(resultCallback)
|
||||
{
|
||||
this.MST = 0;
|
||||
this.edges = [];
|
||||
this.isNotConnected = true;
|
||||
var tempVertices = this.graph.vertices.slice();
|
||||
connectedVertex = getVertexToVertexArray(this.graph, true);
|
||||
|
||||
// We ignore orientation for this algorithm.
|
||||
//if (!this.graph.hasDirectEdge())
|
||||
{
|
||||
res = this.resultStartedFrom(tempVertices[0], connectedVertex);
|
||||
this.isNotConnected = res.isNotConnected;
|
||||
if (!this.isNotConnected)
|
||||
{
|
||||
this.MST = res.MST;
|
||||
this.edges = res.edges;
|
||||
}
|
||||
}
|
||||
/*else
|
||||
{
|
||||
for (var i = 0; i < tempVertices.length; i++)
|
||||
{
|
||||
res = this.resultStartedFrom(tempVertices[i], connectedVertex);
|
||||
if (!res.isNotConnected)
|
||||
{
|
||||
this.isNotConnected = res.isNotConnected;
|
||||
if (this.MST == 0 || res.MST < this.MST)
|
||||
{
|
||||
console.log(res);
|
||||
this.MST = res.MST;
|
||||
this.edges = res.edges;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
result["minPath"] = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MinimumSpanningTree.prototype.resultStartedFrom = function(vertex, connectedVertex)
|
||||
{
|
||||
var res = {};
|
||||
res.MST = 0;
|
||||
res.edges = [];
|
||||
res.isNotConnected = false;
|
||||
|
||||
var inTree = [];
|
||||
inTree.push(vertex);
|
||||
var vertecesInTree = 0;
|
||||
|
||||
// Will break in end of loop
|
||||
while (true)
|
||||
{
|
||||
vertecesInTree++;
|
||||
var minVert = null;
|
||||
var minEdge = null;
|
||||
|
||||
for (i = 0; i < inTree.length; i++)
|
||||
{
|
||||
var element = inTree[i];
|
||||
|
||||
if (connectedVertex.hasOwnProperty(element.id))
|
||||
{
|
||||
for (j = 0; j < connectedVertex[element.id].length; j++)
|
||||
{
|
||||
var connectedElement = connectedVertex[element.id][j];
|
||||
var connectedEdge = this.graph.FindEdgeMinIgnoreDirection(element.id, connectedElement.id);
|
||||
|
||||
if (inTree.indexOf(connectedElement) < 0)
|
||||
{
|
||||
if (minEdge == null || minEdge.weight > connectedEdge.weight)
|
||||
{
|
||||
minEdge = connectedEdge;
|
||||
minVert = connectedElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minVert == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.MST = res.MST + Number(minEdge.weight);
|
||||
inTree.push(minVert);
|
||||
res.edges.push(minEdge);
|
||||
}
|
||||
}
|
||||
|
||||
res.isNotConnected = (inTree.length < this.graph.vertices.length);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
MinimumSpanningTree.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return this.isNotConnected ? 0 :
|
||||
(object instanceof BaseVertex || this.edges.indexOf(object) >= 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
MinimumSpanningTree.prototype.getPriority = function()
|
||||
{
|
||||
return -9.3;
|
||||
}
|
||||
|
||||
// Algorithm support multi graph
|
||||
MinimumSpanningTree.prototype.IsSupportMultiGraph = function ()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Factory for algorithm.
|
||||
function CreateMinimumSpanningTree(graph, app)
|
||||
{
|
||||
return new MinimumSpanningTree(graph)
|
||||
}
|
||||
|
||||
// Register connected component.
|
||||
RegisterAlgorithm (CreateMinimumSpanningTree);
|
||||
|
||||
198
script/features/algorithms/model/plugins/ModernGraphStyle.js
Normal file
198
script/features/algorithms/model/plugins/ModernGraphStyle.js
Normal file
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* Algorithm for modern style of graph.
|
||||
*
|
||||
*/
|
||||
function ModernGraphStyle(graph, app)
|
||||
{
|
||||
BaseAlgorithm.apply(this, arguments);
|
||||
this.minVertexSize = 20;
|
||||
this.maxVertexSize = 100;
|
||||
|
||||
this.minEdgeSize = 2;
|
||||
this.maxEdgeSize = 12;
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
ModernGraphStyle.prototype = Object.create(BaseAlgorithm.prototype);
|
||||
|
||||
|
||||
ModernGraphStyle.prototype.getName = function(local)
|
||||
{
|
||||
return g_modernGraphStyleName;// local == "ru" ? "Визуализация на основе весов" : "Visualisation based on weight";
|
||||
}
|
||||
|
||||
ModernGraphStyle.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.ModernGraphStyle";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
ModernGraphStyle.prototype.getMessage = function(local)
|
||||
{
|
||||
return g_done;
|
||||
}
|
||||
|
||||
ModernGraphStyle.prototype.result = function(resultCallback)
|
||||
{
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
|
||||
this.vertexVisualization2();
|
||||
this.edgeVisualization();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ModernGraphStyle.prototype.vertexVisualization = function()
|
||||
{
|
||||
var degree = getVertexToVertexArray(this.graph, false);
|
||||
var graph = this.graph;
|
||||
var maxDegree = 0;
|
||||
var sumDegree = 0;
|
||||
|
||||
var sumOfDiameters = graph.vertices.length * (new VertexModel()).diameter;
|
||||
|
||||
// Search max vertex degree.
|
||||
for (var i = 0; i < graph.vertices.length; i++)
|
||||
{
|
||||
var vertex = graph.vertices[i];
|
||||
|
||||
if (degree.hasOwnProperty(vertex.id))
|
||||
{
|
||||
var currentDegree = degree[vertex.id].length;
|
||||
maxDegree = Math.max(maxDegree, currentDegree);
|
||||
sumDegree = sumDegree + currentDegree;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (var i = 0; i < graph.vertices.length; i++)
|
||||
{
|
||||
var vertex = graph.vertices[i];
|
||||
|
||||
if (degree.hasOwnProperty(vertex.id))
|
||||
{
|
||||
var currentDegree = degree[vertex.id].length;
|
||||
//vertex.model.diameter = (currentDegree / maxDegree) * (this.maxVertexSize - this.minVertexSize) + this.minVertexSize;
|
||||
vertex.model.diameter = Math.max(Math.min((currentDegree / sumDegree) * sumOfDiameters, this.maxVertexSize), this.minVertexSize);
|
||||
//sumOfDiameters
|
||||
}
|
||||
else
|
||||
{
|
||||
vertex.model.diameter = this.minVertexSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ModernGraphStyle.prototype.vertexVisualization2 = function()
|
||||
{
|
||||
var degree = {};
|
||||
var graph = this.graph;
|
||||
var sumDegree = 0;
|
||||
|
||||
var sumOfDiameters = graph.vertices.length * (new VertexModel()).diameter;
|
||||
|
||||
// Search max vertex degree.
|
||||
for (var i = 0; i < graph.edges.length; i++)
|
||||
{
|
||||
var edge = graph.edges[i];
|
||||
if (!degree.hasOwnProperty(edge.vertex1.id))
|
||||
{
|
||||
degree[edge.vertex1.id] = 0;
|
||||
}
|
||||
if (!degree.hasOwnProperty(edge.vertex2.id))
|
||||
{
|
||||
degree[edge.vertex2.id] = 0;
|
||||
}
|
||||
|
||||
var currentWeight = 0;
|
||||
if (edge.isDirect)
|
||||
{
|
||||
currentWeight = edge.GetWeight() / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentWeight = edge.GetWeight();
|
||||
}
|
||||
|
||||
sumDegree = sumDegree + 2 * currentWeight;
|
||||
degree[edge.vertex1.id] += currentWeight;
|
||||
degree[edge.vertex2.id] += currentWeight;
|
||||
}
|
||||
|
||||
console.log("sumDegree = " + sumDegree);
|
||||
for (var i = 0; i < graph.vertices.length; i++)
|
||||
{
|
||||
var vertex = graph.vertices[i];
|
||||
|
||||
if (degree.hasOwnProperty(vertex.id))
|
||||
{
|
||||
var currentDegree = degree[vertex.id];
|
||||
console.log(currentDegree / sumDegree);
|
||||
vertex.model.diameter = Math.max(Math.min((currentDegree / sumDegree) * sumOfDiameters, this.maxVertexSize), this.minVertexSize);
|
||||
//sumOfDiameters
|
||||
}
|
||||
else
|
||||
{
|
||||
vertex.model.diameter = this.minVertexSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ModernGraphStyle.prototype.edgeVisualization = function()
|
||||
{
|
||||
var graph = this.graph;
|
||||
var maxEdgeWeight = 0;
|
||||
var sumWeight = 0;
|
||||
var sumOfDiameters = graph.edges.length * (new EdgeModel()).width;
|
||||
|
||||
// Search max edge weight.
|
||||
for (var i = 0; i < graph.edges.length; i++)
|
||||
{
|
||||
var edge = graph.edges[i];
|
||||
if (edge.useWeight)
|
||||
{
|
||||
maxEdgeWeight = Math.max(maxEdgeWeight, edge.weight);
|
||||
sumWeight = sumWeight + edge.weight;
|
||||
}
|
||||
}
|
||||
|
||||
// Search max edge weight.
|
||||
if (maxEdgeWeight != 0)
|
||||
{
|
||||
for (var i = 0; i < graph.edges.length; i++)
|
||||
{
|
||||
var edge = graph.edges[i];
|
||||
if (edge.useWeight)
|
||||
{
|
||||
//edge.model.width = (edge.weight / maxEdgeWeight) * (this.maxEdgeSize - this.minEdgeSize) + this.minEdgeSize;
|
||||
edge.model.width = Math.max(Math.min((edge.weight / sumWeight) * sumOfDiameters, this.maxEdgeSize), this.minEdgeSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
edge.model.width = this.minEdgeSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ModernGraphStyle.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Algorithm support multi graph
|
||||
ModernGraphStyle.prototype.IsSupportMultiGraph = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateAlgorithmModernGraphStyle(graph, app)
|
||||
{
|
||||
return new ModernGraphStyle(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateAlgorithmModernGraphStyle);
|
||||
231
script/features/algorithms/model/plugins/RadiusAndDiameter.js
Normal file
231
script/features/algorithms/model/plugins/RadiusAndDiameter.js
Normal file
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* Algorithm for reorder graph.
|
||||
*
|
||||
*/
|
||||
function RadiusAndDiameter(graph, app)
|
||||
{
|
||||
BaseAlgorithm.apply(this, arguments);
|
||||
this.diameter = 0;
|
||||
this.radius = 0;
|
||||
this.diameterSelectedObjects = [];
|
||||
this.radiusSelectedObjects = [];
|
||||
this.centerVertices = [];
|
||||
this.peripheralVertices = [];
|
||||
this.isNotConnected = false;
|
||||
this.isOneVertex = false;
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
RadiusAndDiameter.prototype = Object.create(BaseAlgorithm.prototype);
|
||||
|
||||
|
||||
RadiusAndDiameter.prototype.getName = function(local)
|
||||
{
|
||||
return g_RadiusAndDiameter;
|
||||
}
|
||||
|
||||
RadiusAndDiameter.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.RadiusAndDiameter";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
RadiusAndDiameter.prototype.getMessage = function(local)
|
||||
{
|
||||
if (this.isNotConnected)
|
||||
{
|
||||
return g_graphIsDisconnected;
|
||||
}
|
||||
|
||||
if (this.isOneVertex)
|
||||
{
|
||||
return g_graphIsTrivial;
|
||||
}
|
||||
|
||||
var text = g_graphRadius + ": " + this.radius;
|
||||
|
||||
text = text + " (";
|
||||
for (i = 0; i < this.radiusSelectedObjects.length; i++)
|
||||
{
|
||||
if (this.radiusSelectedObjects[i] instanceof BaseVertex)
|
||||
{
|
||||
text = text + this.radiusSelectedObjects[i].mainText + ((i < this.radiusSelectedObjects.length - 1) ? "⇒" : "");
|
||||
}
|
||||
}
|
||||
text = text + ").";
|
||||
|
||||
text = text + " " + g_graphDiameter + ": " + this.diameter;
|
||||
|
||||
text = text + " (";
|
||||
for (i = 0; i < this.diameterSelectedObjects.length; i++)
|
||||
{
|
||||
if (this.diameterSelectedObjects[i] instanceof BaseVertex)
|
||||
{
|
||||
text = text + this.diameterSelectedObjects[i].mainText + ((i < this.diameterSelectedObjects.length - 1) ? "⇒" : "");
|
||||
}
|
||||
}
|
||||
text = text + ").";
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
RadiusAndDiameter.prototype.result = function(resultCallback)
|
||||
{
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
|
||||
if (this.graph.vertices.length == 1)
|
||||
{
|
||||
this.isOneVertex = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var connectedComponents = new FindConnectedComponentNew(this.graph, this.app);
|
||||
var connectedComponentNumber = connectedComponents.calculate();
|
||||
if (connectedComponentNumber == 1)
|
||||
{
|
||||
var floid = new FloidAlgorithm(this.graph, this.app);
|
||||
var matrix = floid.resultMatrix();
|
||||
this.diameter = -1;
|
||||
var diameterStart = 0;
|
||||
var diameterFinish = 0;
|
||||
|
||||
this.radius = 1E10;
|
||||
var radiusStart = 0;
|
||||
var radiusFinish = 0;
|
||||
|
||||
var eccentricity = [];
|
||||
|
||||
for (var i = 0; i < matrix.length; i++)
|
||||
{
|
||||
var vertex = -1;//(i == 0 ? 1 : 0);
|
||||
var vertexEccentricity = -1;//matrix[i][vertex];
|
||||
|
||||
for (var j = 0; j < matrix[i].length; j++)
|
||||
{
|
||||
if (vertexEccentricity < matrix[i][j] && i != j && matrix[i][j] != floid.infinity)
|
||||
{
|
||||
vertexEccentricity = matrix[i][j];
|
||||
vertex = j;
|
||||
}
|
||||
}
|
||||
|
||||
var res = {value: vertexEccentricity, vertex: vertex};
|
||||
eccentricity.push(res);
|
||||
}
|
||||
|
||||
for (var i = 0; i < eccentricity.length; i++)
|
||||
{
|
||||
var vertexEccentricity = eccentricity[i].value;
|
||||
if (vertexEccentricity < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.radius > vertexEccentricity)
|
||||
{
|
||||
this.radius = vertexEccentricity;
|
||||
radiusStart = i;
|
||||
radiusFinish = eccentricity[i].vertex;
|
||||
}
|
||||
|
||||
if (this.diameter < vertexEccentricity)
|
||||
{
|
||||
this.diameter = vertexEccentricity;
|
||||
diameterStart = i;
|
||||
diameterFinish = eccentricity[i].vertex;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < eccentricity.length; i++)
|
||||
{
|
||||
var vertexEccentricity = eccentricity[i].value;
|
||||
if (vertexEccentricity < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (eccentricity[i].value == this.radius)
|
||||
{
|
||||
this.centerVertices.push(this.graph.vertices[i].id);
|
||||
this.graph.vertices[i].upText = g_vertexCentral;
|
||||
}
|
||||
if (eccentricity[i].value == this.diameter)
|
||||
{
|
||||
this.peripheralVertices.push(this.graph.vertices[i].id);
|
||||
this.graph.vertices[i].upText = g_vertexPeripheral;
|
||||
}
|
||||
}
|
||||
|
||||
this.diameterSelectedObjects = this.getPathByMatrix(this.graph.GetAdjacencyMatrix(), matrix, diameterStart, diameterFinish, this.diameter);
|
||||
|
||||
this.radiusSelectedObjects = this.getPathByMatrix(this.graph.GetAdjacencyMatrix(), matrix, radiusStart, radiusFinish, this.radius);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
this.isNotConnected = true;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
RadiusAndDiameter.prototype.getPathByMatrix = function(adjacencyMatrix, minPathMatrix, startNode, finishNode, length)
|
||||
{
|
||||
var res = [];
|
||||
vertices = this.graph.vertices;
|
||||
while (length != adjacencyMatrix[startNode][finishNode])
|
||||
{
|
||||
for (var i = 0; i < adjacencyMatrix.length; i ++)
|
||||
{
|
||||
if (minPathMatrix[i][finishNode] == length - adjacencyMatrix[startNode][i] && i != startNode)
|
||||
{
|
||||
res.push(vertices[startNode]);
|
||||
res.push(this.graph.FindEdgeMin(vertices[startNode].id, vertices[i].id));
|
||||
|
||||
length -= adjacencyMatrix[startNode][i];
|
||||
startNode = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.push(vertices[startNode]);
|
||||
res.push(this.graph.FindEdgeMin(vertices[startNode].id, vertices[finishNode].id));
|
||||
res.push(vertices[finishNode]);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
RadiusAndDiameter.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
var res = (this.diameterSelectedObjects.includes(object)) ? 1 : 0;
|
||||
res = (this.radiusSelectedObjects.includes(object)) ? 2 : res;
|
||||
//res = (this.centerVertices.includes(object.id)) ? 3 : res;
|
||||
//res = (this.peripheralVertices.includes(object.id)) ? 4 : res;
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
RadiusAndDiameter.prototype.getPriority = function()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Algorithm support multi graph
|
||||
RadiusAndDiameter.prototype.IsSupportMultiGraph = function ()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateAlgorithmRadiusAndDiameter(graph, app)
|
||||
{
|
||||
return new RadiusAndDiameter(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateAlgorithmRadiusAndDiameter);
|
||||
232
script/features/algorithms/model/plugins/ShortestPath.js
Normal file
232
script/features/algorithms/model/plugins/ShortestPath.js
Normal file
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
* Find short path.
|
||||
*
|
||||
*/
|
||||
function FindShortPathNew(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
this.message = g_selectStartVertexForShortPath;
|
||||
this.selectedObjects = {};
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
FindShortPathNew.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
// First selected.
|
||||
FindShortPathNew.prototype.firstObject = null;
|
||||
// Second selected.
|
||||
FindShortPathNew.prototype.secondObject = null;
|
||||
// Path
|
||||
FindShortPathNew.prototype.pathObjects = null;
|
||||
// Infinity
|
||||
FindShortPathNew.prototype.infinityValue = 1E9 - 1;
|
||||
|
||||
FindShortPathNew.prototype.getName = function(local)
|
||||
{
|
||||
return g_findShortPathName; //local == "ru" ? "Поиск кратчайший путь алгоритмом Дейкстры" : "Find shortest path using Dijkstra's algorithm";
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.FindShortestPath";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
FindShortPathNew.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.getCategory = function()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.result = function(resultCallback)
|
||||
{
|
||||
if (this.firstObject && this.secondObject)
|
||||
{
|
||||
this.outResultCallback = function (result ) { resultCallback(result); };
|
||||
self = this;
|
||||
this.CalculateAlgorithm("dsp",
|
||||
[
|
||||
{name: "start", value: this.firstObject.id},
|
||||
{name: "finish", value: this.secondObject.id}
|
||||
], function (pathObjects, properties, results)
|
||||
{
|
||||
self.resultCallback(pathObjects, properties, results);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.resultCallback = function(pathObjects, properties, results)
|
||||
{
|
||||
var outputResult = {};
|
||||
outputResult["version"] = 1;
|
||||
outputResult["minPath"] = true;
|
||||
|
||||
this.pathObjects = pathObjects;
|
||||
this.properties = properties;
|
||||
|
||||
var bFound = results.length > 0 && results[0].value < this.infinityValue && (results[0].type == 1 || results[0].type == 2);
|
||||
|
||||
if (bFound)
|
||||
{
|
||||
this.selectedObjects = {};
|
||||
|
||||
for (var i = 0; i < pathObjects.length; i++)
|
||||
{
|
||||
this.selectedObjects[pathObjects[i].id] = 1;
|
||||
}
|
||||
|
||||
this.message = g_shortestPathResult.replace("%d", (results[0].value * 1).toString());
|
||||
|
||||
var nodesPath = this.GetNodesPath(results, 1, results.length - 1);
|
||||
outputResult["paths"] = [];
|
||||
outputResult["paths"].push(nodesPath);
|
||||
|
||||
this.message = this.message + ": ";
|
||||
for (var i = 0; i < nodesPath.length; i++)
|
||||
{
|
||||
this.message = this.message + this.graph.FindVertex(nodesPath[i]).mainText + ((i < nodesPath.length - 1) ? "⇒" : "");
|
||||
}
|
||||
|
||||
this.message = this.message + " <select style=\"float:right\" id=\"enumReport\"></select>";
|
||||
|
||||
this.updateUpText();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.message = g_pathNotExists;
|
||||
}
|
||||
this.secondObject = null;
|
||||
this.firstObject = null;
|
||||
|
||||
this.outResultCallback(outputResult);
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.selectVertex = function(vertex)
|
||||
{
|
||||
this.pathObjects = null;
|
||||
this.shortDist = null;
|
||||
|
||||
if (this.firstObject)
|
||||
{
|
||||
this.message = g_processing;
|
||||
this.secondObject = vertex;
|
||||
this.selectedObjects = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
this.firstObject = vertex;
|
||||
this.secondObject = null;
|
||||
this.selectedObjects = {};
|
||||
this.message = g_selectFinishVertexForShortPath;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.deselectAll = function()
|
||||
{
|
||||
this.firstObject = null;
|
||||
this.secondObject = null;
|
||||
this.selectedObjects = {};
|
||||
this.message = g_selectStartVertexForShortPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.instance = function()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : ((object == this.firstObject || object == object.secondObject) ? 1 : 0);
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.messageWasChanged = function()
|
||||
{
|
||||
var enumReport = document.getElementById("enumReport");
|
||||
if (enumReport)
|
||||
{
|
||||
var optionFull = document.createElement('option');
|
||||
optionFull.text = g_fullReport;
|
||||
optionFull.value = 0;
|
||||
|
||||
var optionShort = document.createElement('option');
|
||||
optionShort.text = g_shortReport;
|
||||
optionShort.value = 1;
|
||||
|
||||
enumReport.add(optionFull, 0);
|
||||
enumReport.add(optionShort, 1);
|
||||
|
||||
enumReport.selectedIndex = this.app.GetCurrentValue("findShortPathReportType", 1);
|
||||
|
||||
var self = this;
|
||||
enumReport.onchange = function () {
|
||||
self.changedType();
|
||||
self.app.redrawGraph();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FindShortPathNew.prototype.changedType = function()
|
||||
{
|
||||
var enumReport = document.getElementById("enumReport");
|
||||
|
||||
this.app.SetCurrentValue("findShortPathReportType", enumReport.options[enumReport.selectedIndex].value);
|
||||
this.updateUpText();
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.updateUpText = function()
|
||||
{
|
||||
var reportType = this.app.GetCurrentValue("findShortPathReportType", 1);
|
||||
|
||||
if (reportType == 0)
|
||||
{
|
||||
for (var i = 0; i < this.graph.vertices.length; i++)
|
||||
{
|
||||
var object = this.graph.vertices[i];
|
||||
if (this.properties.hasOwnProperty(object.id))
|
||||
{
|
||||
var propertie = this.properties[object.id];
|
||||
if (propertie.hasOwnProperty('lowestDistance'))
|
||||
{
|
||||
object.upText = g_shortestDistance + (propertie.lowestDistance > this.infinityValue ? "\u221E" : (propertie.lowestDistance * 1).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < this.graph.vertices.length; i++)
|
||||
{
|
||||
this.graph.vertices[i].upText = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.getPriority = function()
|
||||
{
|
||||
return -10;
|
||||
}
|
||||
|
||||
// Algorithm support multi graph
|
||||
FindShortPathNew.prototype.IsSupportMultiGraph = function ()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateFindShortPathNew(graph, app)
|
||||
{
|
||||
return new FindShortPathNew(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateFindShortPathNew);
|
||||
102
script/features/algorithms/model/plugins/VerticesDegree.js
Normal file
102
script/features/algorithms/model/plugins/VerticesDegree.js
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Algorithm samble.
|
||||
*
|
||||
*/
|
||||
function VerticesDegree(graph, app)
|
||||
{
|
||||
BaseAlgorithm.apply(this, arguments);
|
||||
this.degree = {};
|
||||
this.maxDegree = 0;
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
VerticesDegree.prototype = Object.create(BaseAlgorithm.prototype);
|
||||
|
||||
|
||||
VerticesDegree.prototype.getName = function(local)
|
||||
{
|
||||
return g_VerticesDegreeName; //local == "ru" ? "Рассчитать степень вершин" : "Calculate vertices degree";
|
||||
}
|
||||
|
||||
VerticesDegree.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.VertexDegree";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
VerticesDegree.prototype.getMessage = function(local)
|
||||
{
|
||||
return g_maximumDegreeOfGraph + " " + this.maxDegree;
|
||||
}
|
||||
|
||||
VerticesDegree.prototype.result = function(resultCallback)
|
||||
{
|
||||
this.degree = {};
|
||||
this.maxDegree = 0;
|
||||
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
|
||||
var graph = this.graph;
|
||||
var thisObj = this;
|
||||
|
||||
var addDegreeToVertex = function (id)
|
||||
{
|
||||
if (thisObj.degree.hasOwnProperty(id))
|
||||
{
|
||||
thisObj.degree[id] ++;
|
||||
currentDegree = thisObj.degree[id];
|
||||
thisObj.maxDegree = Math.max(thisObj.maxDegree, currentDegree);
|
||||
}
|
||||
else
|
||||
{
|
||||
thisObj.degree[id] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < graph.edges.length; i++)
|
||||
{
|
||||
var edge = graph.edges[i];
|
||||
var currentDegree = 0;
|
||||
|
||||
addDegreeToVertex(edge.vertex1.id);
|
||||
if (!edge.isDirect)
|
||||
{
|
||||
addDegreeToVertex(edge.vertex2.id);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < graph.vertices.length; i++)
|
||||
{
|
||||
var vertex = graph.vertices[i];
|
||||
if (!this.degree.hasOwnProperty(vertex.id))
|
||||
{
|
||||
this.degree[vertex.id] = 0;
|
||||
}
|
||||
|
||||
vertex.upText = this.degree[vertex.id];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VerticesDegree.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (this.degree.hasOwnProperty(object.id)) ? this.degree[object.id]: 0;
|
||||
}
|
||||
|
||||
// Algorithm support multi graph
|
||||
VerticesDegree.prototype.IsSupportMultiGraph = function ()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateAlgorithmVerticesDegree(graph, app)
|
||||
{
|
||||
return new VerticesDegree(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateAlgorithmVerticesDegree);
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* Default handler.
|
||||
* Select using mouse, drag.
|
||||
*
|
||||
*/
|
||||
function NeedAlgorithm(graph, app)
|
||||
{
|
||||
BaseAlgorithm.apply(this, arguments);
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
NeedAlgorithm.prototype = Object.create(BaseAlgorithm.prototype);
|
||||
|
||||
|
||||
NeedAlgorithm.prototype.getName = function(local)
|
||||
{
|
||||
return local == "ru" ? "Не нашли нужный алгоритм?" : "Didn't you find the algorithm you need?";
|
||||
}
|
||||
|
||||
NeedAlgorithm.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.NeedAlgorithm";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
NeedAlgorithm.prototype.getMessage = function(local)
|
||||
{
|
||||
return local == "ru" ? "Спасибо" : "Thank you";
|
||||
}
|
||||
|
||||
NeedAlgorithm.prototype.result = function(resultCallback)
|
||||
{
|
||||
/*
|
||||
var dialogButtons = {};
|
||||
|
||||
dialogButtons[g_send] = function() {
|
||||
console.log("Message" + $( "#NeedAlgorithmMessage" ).val());
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "/cgi-bin/sendEmail.php?text=" + $( "#NeedAlgorithmMessage" ).val(),
|
||||
dataType: "text"
|
||||
});
|
||||
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
|
||||
dialogButtons[g_close] = function() {
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
|
||||
$( "#NeedAlgorithm" ).dialog({
|
||||
resizable: false,
|
||||
title: g_recommendAlgorithm,
|
||||
width: 400,
|
||||
modal: true,
|
||||
dialogClass: 'EdgeDialog',
|
||||
buttons: dialogButtons,
|
||||
});
|
||||
*/
|
||||
|
||||
var dialogButtons = {};
|
||||
|
||||
for (var i = 0; i < 6 && document.getElementById('vote' + i) !== null; i++)
|
||||
{
|
||||
document.getElementById('vote' + i)["voteIndex"] = i;
|
||||
document.getElementById('vote' + i).onclick = function ()
|
||||
{
|
||||
console.log("Vote" + this["voteIndex"]);
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "/" + SiteDir + "cgi-bin/vote.php?index=" + this["voteIndex"],
|
||||
dataType: "text"
|
||||
});
|
||||
$("#voteDialog").dialog('close');
|
||||
$("#VoteButton").hide();
|
||||
}
|
||||
}
|
||||
|
||||
dialogButtons[g_close] = function() {
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
|
||||
$( "#voteDialog" ).dialog({
|
||||
resizable: false,
|
||||
title: g_vote,
|
||||
width: 400,
|
||||
modal: true,
|
||||
dialogClass: 'EdgeDialog',
|
||||
buttons: dialogButtons,
|
||||
});
|
||||
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NeedAlgorithm.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
NeedAlgorithm.prototype.getPriority = function()
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateNeedAlgorithm(graph, app)
|
||||
{
|
||||
return new NeedAlgorithm(graph)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateNeedAlgorithm);
|
||||
Reference in New Issue
Block a user