moved
This commit is contained in:
135
Sapfor/_src/VisualizerCalls/BuildGraph.cpp
Normal file
135
Sapfor/_src/VisualizerCalls/BuildGraph.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <assert.h>
|
||||
|
||||
#include "../GraphCall/graph_calls_func.h"
|
||||
#include "graphLayout/nodesoup.hpp"
|
||||
#include "BuildGraph.h"
|
||||
|
||||
using std::map;
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::pair;
|
||||
using std::set;
|
||||
|
||||
using namespace nodesoup;
|
||||
|
||||
static int getNextRandNum(int &N, const int SIZE, int curr)
|
||||
{
|
||||
int ret = N % SIZE;
|
||||
++N;
|
||||
while (ret == curr)
|
||||
{
|
||||
if (SIZE == 1)
|
||||
break;
|
||||
ret = N % SIZE;
|
||||
++N;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
map<string, pair<int, int>>
|
||||
buildLocationOfGraph(const map<string, vector<FuncInfo*>>& allFuncInfo, const int iters, const int coef,
|
||||
const unsigned int width, const unsigned int height, const set<string>* visible)
|
||||
{
|
||||
if (visible && visible->size() == 0)
|
||||
return map<string, pair<int, int>>();
|
||||
|
||||
map<string, FuncInfo*> mapOfFuncs;
|
||||
createMapOfFunc(allFuncInfo, mapOfFuncs);
|
||||
|
||||
map<string, int> num;
|
||||
|
||||
int z = 0;
|
||||
for (auto& elem : mapOfFuncs)
|
||||
{
|
||||
if (visible && visible->find(elem.first) == visible->end())
|
||||
continue;
|
||||
num[elem.first] = z++;
|
||||
}
|
||||
|
||||
for (auto& elem : mapOfFuncs)
|
||||
{
|
||||
set<string> callsFrom;
|
||||
for (auto& callFromInfo : elem.second->callsFromDetailed)
|
||||
{
|
||||
auto& callFrom_ = callFromInfo.detailCallsFrom;
|
||||
callsFrom.insert(callFrom_.first);
|
||||
}
|
||||
callsFrom.insert(elem.second->externalCalls.begin(), elem.second->externalCalls.end());
|
||||
|
||||
for (auto& call : callsFrom)
|
||||
{
|
||||
if (visible && visible->find(call) == visible->end())
|
||||
continue;
|
||||
if (num.find(call) == num.end())
|
||||
num[call] = z++;
|
||||
}
|
||||
}
|
||||
|
||||
adj_list_t g;
|
||||
g.resize(z);
|
||||
|
||||
vector<Point2D> positions;
|
||||
vector<double> radiuses = size_radiuses(g);
|
||||
|
||||
set<pair<string, string>> edges;
|
||||
for (auto& elem : mapOfFuncs)
|
||||
{
|
||||
if (visible && visible->find(elem.first) == visible->end())
|
||||
continue;
|
||||
|
||||
set<string> callsFrom;
|
||||
for (auto& callFromInfo : elem.second->callsFromDetailed)
|
||||
{
|
||||
auto& callFrom_ = callFromInfo.detailCallsFrom;
|
||||
callsFrom.insert(callFrom_.first);
|
||||
}
|
||||
callsFrom.insert(elem.second->externalCalls.begin(), elem.second->externalCalls.end());
|
||||
|
||||
for (auto& call : callsFrom)
|
||||
{
|
||||
if (visible && visible->find(call) == visible->end())
|
||||
continue;
|
||||
|
||||
const pair<string, string> key = make_pair(elem.first, call);
|
||||
if (edges.find(key) == edges.end())
|
||||
{
|
||||
edges.insert(key);
|
||||
g[num[elem.first]].push_back(num[call]);
|
||||
g[num[call]].push_back(num[elem.first]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (z == 1)
|
||||
{
|
||||
map<string, pair<int, int>> result;
|
||||
if (num.size() != 1)
|
||||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||||
|
||||
for (auto& elem : num)
|
||||
result[elem.first] = std::make_pair(width / 2, height / 2);
|
||||
return result;
|
||||
}
|
||||
|
||||
positions = fruchterman_reingold(g, width, height, iters, coef);
|
||||
|
||||
map<string, pair<int, int>> result;
|
||||
for (auto& elem : num)
|
||||
result[elem.first] = positions[num[elem.first]].toPair();
|
||||
return result;
|
||||
}
|
||||
3
Sapfor/_src/VisualizerCalls/BuildGraph.h
Normal file
3
Sapfor/_src/VisualizerCalls/BuildGraph.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
std::map<std::string, std::pair<int, int>> buildLocationOfGraph(const std::map<std::string, std::vector<FuncInfo*>>& allFuncInfo, const int iters = 1000, const int coef = 100, const unsigned int width = 1920, const unsigned int height = 1080, const std::set<std::string>* visible = NULL);
|
||||
531
Sapfor/_src/VisualizerCalls/SendMessage.cpp
Normal file
531
Sapfor/_src/VisualizerCalls/SendMessage.cpp
Normal file
@@ -0,0 +1,531 @@
|
||||
#include <string>
|
||||
#include <locale>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
|
||||
#include "SendMessage.h"
|
||||
#include "../Utils/utils.h"
|
||||
#include "get_information.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <winsock.h>
|
||||
|
||||
#define WM_USER 0x0400 //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
#define STATUS_MESSAGE WM_USER + 16
|
||||
|
||||
// link with Ws2_32.lib
|
||||
#pragma comment(lib,"Ws2_32.lib")
|
||||
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define SOCKET int
|
||||
#define INVALID_SOCKET (SOCKET)(~0)
|
||||
#define SOCKADDR sockaddr
|
||||
#define closesocket close
|
||||
|
||||
void WSACleanup() { }
|
||||
int WSAGetLastError() { return 0; }
|
||||
void Sleep(int millisec) { usleep(millisec * 1000); }
|
||||
|
||||
#endif
|
||||
|
||||
using std::wstring;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::chrono::high_resolution_clock;
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::milliseconds;
|
||||
|
||||
static SOCKET clientSocket = INVALID_SOCKET;
|
||||
static FILE* logFile = NULL;
|
||||
|
||||
#if _WIN32
|
||||
#define FILE_LOG "Components\\Sapfor_log.txt"
|
||||
#else
|
||||
#define FILE_LOG "Components/Sapfor_log.txt"
|
||||
#endif
|
||||
|
||||
#define __print(prefix, format, ...) do { } while (0)
|
||||
#define __print_log(file, format, ...) do { } while (0)
|
||||
|
||||
/*#define __print(prefix, format, ...) do {\
|
||||
printf((string("%s: ") + format + string("\n")).c_str(), prefix, ##__VA_ARGS__); \
|
||||
fflush(NULL); \
|
||||
} while (0)
|
||||
|
||||
#define __print_log(file, format, ...) do {\
|
||||
if (file) { \
|
||||
time_t now = time(0);\
|
||||
auto dt = string(ctime(&now)); \
|
||||
dt = dt.erase(dt.size() - 1); \
|
||||
fprintf(file, (string("%s: ") + format + string("\n")).c_str(), dt.c_str(), ##__VA_ARGS__); \
|
||||
fflush(file); \
|
||||
} \
|
||||
} while (0)
|
||||
*/
|
||||
#define CLIENT "[SAPFOR]"
|
||||
|
||||
static int doRecv(SOCKET& soc, string& command)
|
||||
{
|
||||
int count = 0; //<2F><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
int err = 0; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||
const int maxSize = 4096; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||
char* buf = NULL; //<2F><><EFBFBD><EFBFBD><EFBFBD>
|
||||
do
|
||||
{
|
||||
buf = new char[maxSize + 1];
|
||||
err = recv(soc, buf, maxSize, 0);
|
||||
if (err > 0)
|
||||
{
|
||||
count += err;
|
||||
buf[err] = '\0';
|
||||
command += buf;
|
||||
}
|
||||
delete[] buf;
|
||||
buf = NULL;
|
||||
|
||||
} while (err > 0 && command.back() != '\n');
|
||||
__print(CLIENT, "'%s' length='%d'\n", command.c_str(), command.length());
|
||||
return err < 0 ? err : count;
|
||||
}
|
||||
|
||||
static int decodeMessage(const string& message, vector<string>& pars, int &winH, int countPars)
|
||||
{
|
||||
int sI = 0;
|
||||
for (int z = 0; z < countPars; ++z)
|
||||
{
|
||||
string d = "";
|
||||
for ( ;sI != message.size() && message[sI] != ' '; ++sI)
|
||||
d += message[sI];
|
||||
if (sI == message.size())
|
||||
return -1;
|
||||
++sI;
|
||||
|
||||
int countElems = -1;
|
||||
if (sscanf(d.c_str(), "%d", &countElems) != 1)
|
||||
return -2;
|
||||
|
||||
string par = "";
|
||||
|
||||
for (int z = 0; sI != message.size() && z < countElems; ++z, ++sI)
|
||||
par += message[sI];
|
||||
if (sI == message.size())
|
||||
return -3;
|
||||
pars.push_back(par);
|
||||
}
|
||||
|
||||
string d = "", toPrint = "";
|
||||
for (; sI != message.size() && message[sI] != ' '; ++sI)
|
||||
d += message[sI];
|
||||
|
||||
if (d[d.size() - 1] == '\n' && d.size() >= 2)
|
||||
toPrint = d.substr(0, d.size() - 2);
|
||||
else
|
||||
toPrint = d;
|
||||
|
||||
__print(CLIENT, "Read port from '%s'", toPrint.c_str());
|
||||
if (sscanf(d.c_str(), "%d", &winH) != 1)
|
||||
{
|
||||
__print(CLIENT, "PORT ERROR");
|
||||
return -4;
|
||||
}
|
||||
else
|
||||
__print(CLIENT, "PORT = %d", winH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sendMessage_1lvl(const wstring& toSend) { MessageManager::sendFirstLvl (toSend); }
|
||||
void sendMessage_2lvl(const wstring& toSend) { MessageManager::sendSecondLvl(toSend); }
|
||||
void sendMessage_progress(const wstring& toSend) { MessageManager::sendProgress (toSend); }
|
||||
|
||||
static string utf8_encode(const wstring& wstr)
|
||||
{
|
||||
if (wstr.empty())
|
||||
return string();
|
||||
#ifdef _WIN32
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
|
||||
string strTo(size_needed, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
|
||||
#else
|
||||
/*char* buf = NULL;
|
||||
int size_needed = wcstombs(buf, wstr.c_str(), sizeof(char));
|
||||
printf("%d for \n", size_needed);
|
||||
buf = new char[size_needed + 1];
|
||||
wcstombs(buf, wstr.c_str(), sizeof(char));
|
||||
string strTo(buf);
|
||||
delete[] buf;*/
|
||||
|
||||
string strTo(wstr.size(), 0);
|
||||
for (int z = 0; z < wstr.size(); ++z)
|
||||
strTo[z] = wstr[z];
|
||||
#endif
|
||||
return strTo;
|
||||
}
|
||||
|
||||
/*static wstring utf8_decode(const string& str)
|
||||
{
|
||||
if (str.empty())
|
||||
return wstring();
|
||||
|
||||
int size_needed = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0);
|
||||
wstring wstr;
|
||||
wstr.resize(size_needed, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &wstr[0], size_needed);
|
||||
return wstr;
|
||||
}*/
|
||||
|
||||
void MessageManager::sendMessage(const wstring& toSend)
|
||||
{
|
||||
if (WinHandler > 0) //to C#
|
||||
{
|
||||
#ifdef _WIN32
|
||||
cachedMessages.push_back(toSend);
|
||||
PostMessage((HWND)WinHandler, STATUS_MESSAGE, (WPARAM)(cachedMessages.back().c_str()), (LPARAM)cachedMessages.back().size());
|
||||
#endif
|
||||
}
|
||||
else if (WinHandler < -1) // to JAVA
|
||||
{
|
||||
vector<wstring> splited;
|
||||
splitString(toSend, '\n', splited);
|
||||
|
||||
int i = 1;
|
||||
for (auto& elem : splited)
|
||||
{
|
||||
string result = utf8_encode(L"message_" + std::to_wstring(i++) + L":" + elem + L"\n");
|
||||
const char* ret = result.c_str();
|
||||
|
||||
int size = result.size();
|
||||
#ifdef _WIN32
|
||||
int iResult = send(clientSocket, ret, size, 0);
|
||||
#else
|
||||
int iResult = write(clientSocket, ret, size);
|
||||
#endif
|
||||
if (iResult < 0)
|
||||
printf("Wrong send is %d\n", iResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int connectAndCreate(SOCKET& socket_t, string address, int port)
|
||||
{
|
||||
socket_t = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (socket_t == INVALID_SOCKET)
|
||||
{
|
||||
printf("Wrong socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sockaddr_in clientService;
|
||||
clientService.sin_family = AF_INET;
|
||||
clientService.sin_addr.s_addr = inet_addr(address.c_str());
|
||||
clientService.sin_port = htons(port);
|
||||
int result = connect(socket_t, (SOCKADDR*)(&clientService), sizeof(clientService));
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
__print(CLIENT, "Wrong connect to socket %d\n", WSAGetLastError());
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MessageManager::setWinHandler(const int winH)
|
||||
{
|
||||
if (winH < -1) // to JAVA
|
||||
{
|
||||
if (MessageManager::init() != 0)
|
||||
{
|
||||
WinHandler = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
__print(CLIENT, "set handler with PORT = %d", winH);
|
||||
if (connectAndCreate(clientSocket, "127.0.0.1", winH == -2 ? 8888 : -winH) != 0)
|
||||
{
|
||||
WinHandler = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
else if (winH == -1 && WinHandler < -1) // close JAVA
|
||||
{
|
||||
if (Started == 0)
|
||||
{
|
||||
Sleep(100);
|
||||
closesocket(clientSocket);
|
||||
clientSocket == INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
WinHandler = winH;
|
||||
}
|
||||
|
||||
//from get_information.cpp
|
||||
extern bool showDebug;
|
||||
|
||||
static int send(SOCKET& client, const wstring& messageIn)
|
||||
{
|
||||
wstring message = messageIn;
|
||||
for (int z = 0; z < message.size(); ++z)
|
||||
if (message[z] == L'\n')
|
||||
message[z] = 1;
|
||||
message += L"\n";
|
||||
|
||||
string result = utf8_encode(message);
|
||||
string size = std::to_string(result.size());
|
||||
|
||||
if (showDebug)
|
||||
{
|
||||
wprintf(L"%s: Original message '%s'", CLIENT, message.c_str());
|
||||
printf("%s: Converted message '%s'", CLIENT, result.c_str());
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int err = send(client, size.c_str(), size.size(), 0);
|
||||
#else
|
||||
size += "\n";
|
||||
int err = write(client, size.c_str(), size.size());
|
||||
#endif
|
||||
__print(CLIENT, "Send message size: %d", (int)result.size());
|
||||
if (err != size.size())
|
||||
{
|
||||
__print(CLIENT, "Error of send(): %d", err); // exit
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buf;
|
||||
recv(client, &buf, 1, 0);
|
||||
|
||||
__print(CLIENT, "send start\n", CLIENT);
|
||||
auto timeForPass = high_resolution_clock::now();
|
||||
#ifdef _WIN32
|
||||
err = send(client, result.c_str(), result.size(), 0);
|
||||
#else
|
||||
err = write(client, result.c_str(), result.size());
|
||||
#endif
|
||||
|
||||
const float elapsed = duration_cast<milliseconds>(high_resolution_clock::now() - timeForPass).count() / 1000.;
|
||||
__print(CLIENT, "send end with time %f sec\n", elapsed);
|
||||
__print(CLIENT, "Send message with size %d", (int)result.size());
|
||||
|
||||
if (err != result.size())
|
||||
{
|
||||
__print(CLIENT, "Error of send(): %d", err); // exit
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = recv(client, &buf, 1, 0);
|
||||
if (err != 1)
|
||||
{
|
||||
__print(CLIENT, "Error of recv(): %d", err); // exit
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MessageManager::sendProgress(const std::wstring& str)
|
||||
{
|
||||
if (WinHandler < -1) // to JAVA
|
||||
{
|
||||
string result = utf8_encode(L"progress:" + str + L"\n");
|
||||
const char* ret = result.c_str();
|
||||
|
||||
int size = result.size();
|
||||
#ifdef _WIN32
|
||||
int iResult = send(clientSocket, ret, size, 0);
|
||||
#else
|
||||
int iResult = write(clientSocket, ret, size);
|
||||
#endif
|
||||
if (iResult == -1)
|
||||
__print(CLIENT, "Error of send(): %d", iResult);
|
||||
}
|
||||
}
|
||||
|
||||
int MessageManager::init()
|
||||
{
|
||||
#if _WIN32
|
||||
if (Started == -1)
|
||||
{
|
||||
WSADATA wsaData = { 0 };
|
||||
int result = WSAStartup(MAKEWORD(2, 0), &wsaData);
|
||||
if (result != 0)
|
||||
{
|
||||
__print(CLIENT, "Wrong WSAStartup(): %d", result);
|
||||
Started = -2;
|
||||
}
|
||||
else
|
||||
Started = 0;
|
||||
}
|
||||
#else
|
||||
Started = 0;
|
||||
#endif
|
||||
return Started;
|
||||
}
|
||||
|
||||
SOCKET client = INVALID_SOCKET;
|
||||
|
||||
void sendErrorCode(const wstring& message)
|
||||
{
|
||||
send(client, message);
|
||||
closesocket(client);
|
||||
client = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
void RunSapforAsClient(int serverPort)
|
||||
{
|
||||
if (MessageManager::init() != 0)
|
||||
return;
|
||||
|
||||
logFile = fopen(FILE_LOG, "w");
|
||||
if (logFile == NULL)
|
||||
__print(CLIENT, "Can not open log file '%s'", FILE_LOG);
|
||||
|
||||
client = INVALID_SOCKET;
|
||||
__print_log(logFile, "create and connect to server socket with port %d", serverPort > 0 ? serverPort : 8889);
|
||||
if (connectAndCreate(client, "127.0.0.1", serverPort > 0 ? serverPort : 8889) != 0)
|
||||
return;
|
||||
__print_log(logFile, "done");
|
||||
|
||||
__print_log(logFile, "start main communications");
|
||||
while (true)
|
||||
{
|
||||
wstring result = L"";
|
||||
string message = "";
|
||||
|
||||
__print(CLIENT, "start recv message");
|
||||
__print_log(logFile, "wait for command from server");
|
||||
|
||||
const int count = doRecv(client, message);
|
||||
|
||||
__print(CLIENT, "end recv message with size %d", count);
|
||||
__print_log(logFile, "done with message size %d", count);
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
string code;
|
||||
/*string copy = message;
|
||||
if (copy.back() == '\n')
|
||||
copy = copy.erase(copy.size() - 1);
|
||||
__print(CLIENT, "Recv message: '%s'", copy.c_str());*/
|
||||
|
||||
int z = 0;
|
||||
for (; z < message.size(); ++z)
|
||||
{
|
||||
if (message[z] == ':')
|
||||
{
|
||||
z++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
code += message[z];
|
||||
}
|
||||
|
||||
if (z == message.size()) // wrong message
|
||||
{
|
||||
__print(CLIENT, "Wrong message");
|
||||
|
||||
__print_log(logFile, "send WRONG message to server ");
|
||||
int err = send(client, L"WRONG");
|
||||
__print_log(logFile, "done with code %d", err);
|
||||
if (err != 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
message = message.substr(z);
|
||||
|
||||
vector<string> pars;
|
||||
int winHandler = -1;
|
||||
|
||||
if (code == "analysis")
|
||||
{
|
||||
__print_log(logFile, "decode message as analysis");
|
||||
int err = decodeMessage(message, pars, winHandler, 3);
|
||||
|
||||
if (err == 0)
|
||||
result = Sapfor_RunAnalysis(pars[0].c_str(), pars[1].c_str(), pars[2].c_str(), winHandler);
|
||||
else
|
||||
result = Sapfor_RunAnalysis(NULL, NULL, NULL, -1);
|
||||
}
|
||||
else if (code == "transformation")
|
||||
{
|
||||
__print_log(logFile, "decode message as transformation");
|
||||
int err = decodeMessage(message, pars, winHandler, 5);
|
||||
if (err == 0)
|
||||
result = Sapfor_RunTransformation(pars[0].c_str(), pars[1].c_str(), pars[2].c_str(), pars[3].c_str(), pars[4].c_str(), winHandler);
|
||||
else
|
||||
result = Sapfor_RunTransformation(NULL, NULL, NULL, NULL, NULL, -1);
|
||||
}
|
||||
else if (code == "modification")
|
||||
{
|
||||
__print_log(logFile, "decode message as modification");
|
||||
int err = decodeMessage(message, pars, winHandler, 6);
|
||||
if (err == 0)
|
||||
result = Sapfor_RunModification(pars[0].c_str(), pars[1].c_str(), pars[2].c_str(), pars[3].c_str(), pars[4].c_str(), pars[5].c_str(), winHandler);
|
||||
else
|
||||
result = Sapfor_RunModification(NULL, NULL, NULL, NULL, NULL, NULL, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
__print(CLIENT, "Wrong code of message: %s", code.c_str()); // exit
|
||||
__print_log(logFile, "wrong code of message, send WRONG");
|
||||
int err = send(client, L"WRONG");
|
||||
__print_log(logFile, "done with code %d", err);
|
||||
|
||||
if (err != 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
__print_log(logFile, "send results to server");
|
||||
int err = send(client, result.c_str());
|
||||
__print_log(logFile, "done with code %d", err);
|
||||
|
||||
if (err != 0)
|
||||
break;
|
||||
}
|
||||
else if (count == 0) // close and exit
|
||||
{
|
||||
closesocket(client);
|
||||
__print(CLIENT, "Socket was closed");
|
||||
__print_log(logFile, "done with normal exit");
|
||||
break;
|
||||
}
|
||||
else // error
|
||||
{
|
||||
closesocket(client);
|
||||
__print(CLIENT, "Recv return error code %d", count);
|
||||
__print_log(logFile, "done with error exit");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int GetPid()
|
||||
{
|
||||
unsigned int pid = 0;
|
||||
#ifdef _WIN32
|
||||
pid = GetCurrentProcessId();
|
||||
#else
|
||||
pid = getpid();
|
||||
#endif
|
||||
return pid;
|
||||
}
|
||||
|
||||
vector<wstring> MessageManager::cachedMessages = vector<wstring>();
|
||||
int MessageManager::WinHandler = -1;
|
||||
wstring MessageManager::firstLvlMessage = L"";
|
||||
wstring MessageManager::secondLvlMessage = L"";
|
||||
int MessageManager::Started = -1;
|
||||
38
Sapfor/_src/VisualizerCalls/SendMessage.h
Normal file
38
Sapfor/_src/VisualizerCalls/SendMessage.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class MessageManager
|
||||
{
|
||||
private:
|
||||
static std::vector<std::wstring> cachedMessages;
|
||||
static int WinHandler;
|
||||
static int Started;
|
||||
static std::wstring firstLvlMessage;
|
||||
static std::wstring secondLvlMessage;
|
||||
|
||||
static void sendMessage(const std::wstring &toSend);
|
||||
public:
|
||||
static void clearCache() { cachedMessages.clear(); }
|
||||
static void setWinHandler(const int winH);
|
||||
static void sendFirstLvl(const std::wstring &str)
|
||||
{
|
||||
firstLvlMessage = str;
|
||||
sendMessage(firstLvlMessage);
|
||||
}
|
||||
|
||||
static void sendSecondLvl(const std::wstring &str)
|
||||
{
|
||||
secondLvlMessage = str;
|
||||
sendMessage(firstLvlMessage + L"\n" + secondLvlMessage);
|
||||
}
|
||||
|
||||
static void sendProgress(const std::wstring& str);
|
||||
static int init();
|
||||
};
|
||||
|
||||
void sendMessage_1lvl(const std::wstring& toSend);
|
||||
void sendMessage_2lvl(const std::wstring& toSend);
|
||||
void sendMessage_progress(const std::wstring& toSend);
|
||||
unsigned int GetPid();
|
||||
2822
Sapfor/_src/VisualizerCalls/get_information.cpp
Normal file
2822
Sapfor/_src/VisualizerCalls/get_information.cpp
Normal file
File diff suppressed because it is too large
Load Diff
67
Sapfor/_src/VisualizerCalls/get_information.h
Normal file
67
Sapfor/_src/VisualizerCalls/get_information.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#if _WIN32
|
||||
// ANALISYS
|
||||
extern "C" { __declspec(dllexport) int SPF_GetGraphLoops(void*& context, int winHandler, short *options, short *projName, short *&result, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_GetGraphFunctions(void*& context, int winHandler, short *options, short *projName, short *&result, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_GetGraphVizOfFunctions(void*& context, short *options, short *projName, short *&result, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_GetArrayDistribution(void*& context, int winHandler, short *options, short *projName, short *&result, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize, int onlyAnalysis); }
|
||||
extern "C" { __declspec(dllexport) int SPF_SetFunctionsToInclude(void*& context, int winHandler, short *options, short *projName, short *&result, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_GetAllDeclaratedArrays(void*& context, int winHandler, short *options, short *projName, short *&result, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_GetFileLineInfo(void*& context, int winHandler, short *options, short *projName, short *&result, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_GetIncludeDependencies(void*& context, int winHandler, short *options, short *projName, short *&resultt, short*& output, int*& outputSize, short*& outputMessage, int*& outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_GetGCovInfo(void*& context, int winHandler, short *options, short *projName, short *&result, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_ParseFiles(void*& context, int winHandler, short *options, short* projName, short*& output, int*& outputSize, short*& outputMessage, int*& outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_StatisticAnalyzer(void*& context, int winHandler, short* options, short* pppaOptions, short*& output, int*& outputSize, short*& outputMessage, int*& outputMessageSize); }
|
||||
|
||||
extern "C" { __declspec(dllexport) int SPF_GetPassesState(void*& context, int *&passInfo); } // deprecated
|
||||
extern "C" { __declspec(dllexport) int SPF_GetPassesStateStr(void*& context, short *&passInfo); }
|
||||
extern "C" { __declspec(dllexport) int SPF_GetVersionAndBuildDate(void*& context, short *&result); }
|
||||
extern "C" { __declspec(dllexport) int SPF_GetIntrinsics(void*& context, short *&result); }
|
||||
extern "C" { __declspec(dllexport) void SPF_deleteAllAllocatedData(void*& context); }
|
||||
|
||||
// CODE TRANSFORMATION
|
||||
extern "C" { __declspec(dllexport) int SPF_CorrectCodeStylePass (void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_RemoveDvmDirectives (void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_RemoveDvmDirectivesToComments (void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_InsertIncludesPass (void*& context, int winHandler, short *options, short *projName, short *folderName, char *filesToInclude, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_ResolveParallelRegionConflicts(void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_LoopEndDoConverterPass (void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_CreateParallelVariant (void*& context, int winHandler, short *options, short *projName, short *folderName, int64_t *variants, int *varLen, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize, short *&predictorStats); }
|
||||
extern "C" { __declspec(dllexport) int SPF_LoopFission (void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_LoopUnion (void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_PrivateExpansion (void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_PrivateShrinking (void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_PrivateRemoving (void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_CreateIntervalsTree (void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_RemoveDvmIntervals (void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_DuplicateFunctionChains (void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int *&outputSize, short *&outputMessage, int *&outputMessageSize); }
|
||||
extern "C" { __declspec(dllexport) int SPF_InlineProcedures (void*& context, int winHandler, short *options, short *projName, short *folderName, short *names, short *&output, int*& outputSize, short*& outputMessage, int*& outputMessageSize, int type); }
|
||||
int SPF_CreateCheckpoints (void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int*& outputSize, short*& outputMessage, int*& outputMessageSize);
|
||||
int SPF_InitDeclsWithZero (void*& context, int winHandler, short *options, short *projName, short *folderName, short *&output, int*& outputSize, short*& outputMessage, int*& outputMessageSize);
|
||||
//CODE MODIFICATION
|
||||
extern "C" { __declspec(dllexport) int SPF_ModifyArrayDistribution (void*& context, int winHandler, short *options, short* projName, short*& output, int*& outputSize, short*& outputMessage, int*& outputMessageSize, int regId, int64_t* toModify); }
|
||||
extern "C" { __declspec(dllexport) int SPF_InlineProcedure (void*& context, int winHandler, short* options, short* projName, short* folderName, short* name, short* file, int line, short*& output, int*& outputSize, short*& outputMessage, int*& outputMessageSize, int& size, int*& sizes, short*& newFilesNames, short*& newFiles); }
|
||||
extern "C" { __declspec(dllexport) int SPF_LoopUnionCurrent (void*& context, int winHandler, short* options, short* projName, short* folderName, short* file, int line, short*& output, int*& outputSize, short*& outputMessage, int*& outputMessageSize, int& size, int*& sizes, short*& newFilesNames, short*& newFiles); }
|
||||
extern "C" { __declspec(dllexport) int SPF_ChangeSpfIntervals (void*& context, int winHandler, short* options, short* projName, short* folderName, short*& output, int*& outputSize, short*& outputMessage, int*& outputMessageSize, short* fileNameToMod, int* toModifyLines, int& size, int*& sizes, short*& newFilesNames, short*& newFiles); }
|
||||
extern "C" { __declspec(dllexport) int SPF_SetDistributionFlagToArray (void*& context, char* key, int flag); }
|
||||
extern "C" { __declspec(dllexport) int SPF_SetDistributionFlagToArrays(void*& context, const char* keys, const char* flags); }
|
||||
#endif
|
||||
|
||||
void createNeededException();
|
||||
void RunSapforAsClient(int);
|
||||
|
||||
const std::wstring Sapfor_RunAnalysis(const char* name, const char* options_c, const char* projName_c, int winHandler);
|
||||
const std::wstring Sapfor_RunTransformation(const char* name, const char* options_c, const char* projName_c, const char* folder_c, const char* addOpt_c, int winHandler);
|
||||
const std::wstring Sapfor_RunModification(const char* name, const char* options_c, const char* projName_c, const char* folder_c, const char* addOpt1_c, const char* addOpt2_c, int winHandler);
|
||||
void sendErrorCode(const std::wstring& message);
|
||||
|
||||
#ifdef JAVA
|
||||
#include <jni.h>
|
||||
extern "C"
|
||||
{
|
||||
JNIEXPORT jcharArray JNICALL Java_components_Sapfor_SPF_1RunAnalysis (JNIEnv*, jobject, jstring, jint, jstring, jstring);
|
||||
JNIEXPORT jcharArray JNICALL Java_components_Sapfor_SPF_1RunTransformation(JNIEnv*, jobject, jstring, jint, jstring, jstring, jstring, jstring);
|
||||
JNIEXPORT jcharArray JNICALL Java_components_Sapfor_SPF_1RunModification (JNIEnv*, jobject, jstring, jint, jstring, jstring, jstring, jstring, jstring);
|
||||
}
|
||||
#endif
|
||||
89
Sapfor/_src/VisualizerCalls/graphLayout/algebra.cpp
Normal file
89
Sapfor/_src/VisualizerCalls/graphLayout/algebra.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include <cmath>
|
||||
|
||||
#include "algebra.hpp"
|
||||
|
||||
namespace nodesoup {
|
||||
|
||||
Point2D::operator Vector2D() const {
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
Point2D& Point2D::operator+=(const Vector2D& vector) {
|
||||
x += vector.dx;
|
||||
y += vector.dy;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Point2D& Point2D::operator-=(const Vector2D& vector) {
|
||||
x -= vector.dx;
|
||||
y -= vector.dy;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector2D::operator Point2D() const {
|
||||
return { dx, dy };
|
||||
}
|
||||
|
||||
Vector2D& Vector2D::operator+=(const Vector2D& other) {
|
||||
dx += other.dx;
|
||||
dy += other.dy;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector2D& Vector2D::operator-=(const Vector2D& other) {
|
||||
dx -= other.dx;
|
||||
dy -= other.dy;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector2D& Vector2D::operator*=(double scalar) {
|
||||
dx *= scalar;
|
||||
dy *= scalar;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector2D& Vector2D::operator*(const Vector2D& other)
|
||||
{
|
||||
dx *= other.dx;
|
||||
dy *= other.dy;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector2D& Vector2D::operator/=(double scalar) {
|
||||
dx /= scalar;
|
||||
dy /= scalar;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Point2D operator+(const Point2D& point, const Vector2D& vector) {
|
||||
return { point.x + vector.dx, point.y + vector.dy };
|
||||
}
|
||||
|
||||
Point2D operator-(const Point2D& point, const Vector2D& vector) {
|
||||
return { point.x - vector.dx, point.y - vector.dy };
|
||||
}
|
||||
|
||||
Vector2D operator-(const Point2D& lhs, const Point2D& rhs) {
|
||||
return { lhs.x - rhs.x, lhs.y - rhs.y };
|
||||
}
|
||||
|
||||
Vector2D operator+(const Vector2D& lhs, const Vector2D& rhs) {
|
||||
return { lhs.dx + rhs.dx, lhs.dy + rhs.dy };
|
||||
}
|
||||
|
||||
Vector2D operator-(const Vector2D& lhs, const Vector2D& rhs) {
|
||||
return { lhs.dx - rhs.dx, lhs.dy - rhs.dy };
|
||||
}
|
||||
|
||||
Vector2D operator*(const Vector2D& vector, double scalar) {
|
||||
return { vector.dx * scalar, vector.dy * scalar };
|
||||
}
|
||||
|
||||
Vector2D operator*(double scalar, const Vector2D& vector) {
|
||||
return vector * scalar;
|
||||
}
|
||||
|
||||
Vector2D operator/(const Vector2D& vector, double scalar) {
|
||||
return { vector.dx / scalar, vector.dy / scalar };
|
||||
}
|
||||
}
|
||||
14
Sapfor/_src/VisualizerCalls/graphLayout/algebra.hpp
Normal file
14
Sapfor/_src/VisualizerCalls/graphLayout/algebra.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "nodesoup.hpp"
|
||||
|
||||
namespace nodesoup {
|
||||
|
||||
Point2D operator+(const Point2D& point, const Vector2D& vector);
|
||||
Point2D operator-(const Point2D& point, const Vector2D& vector);
|
||||
Vector2D operator-(const Point2D& lhs, const Point2D& rhs);
|
||||
Vector2D operator+(const Vector2D lhs, const Vector2D& rhs);
|
||||
Vector2D operator-(const Vector2D& l, const Vector2D& rhs);
|
||||
Vector2D operator*(const Vector2D& vector, double scalar);
|
||||
Vector2D operator*(double scalar, const Vector2D& vector);
|
||||
Vector2D operator/(const Vector2D& vector, double scalar);
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "fruchterman_reingold.hpp"
|
||||
#include "algebra.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
namespace nodesoup {
|
||||
|
||||
using std::vector;
|
||||
|
||||
FruchtermanReingold::FruchtermanReingold(const adj_list_t& g, double k)
|
||||
: g_(g)
|
||||
, k_(k)
|
||||
, k_squared_(k * k)
|
||||
, temp_(10 * sqrt(g.size()))
|
||||
, mvmts_(g_.size()) {}
|
||||
|
||||
void FruchtermanReingold::operator()(vector<Point2D>& positions) {
|
||||
Vector2D zero = { 0.0, 0.0 };
|
||||
fill(mvmts_.begin(), mvmts_.end(), zero);
|
||||
|
||||
// Repulsion force between vertice pairs
|
||||
for (vertex_id_t v_id = 0; v_id < g_.size(); v_id++) {
|
||||
for (vertex_id_t other_id = v_id + 1; other_id < g_.size(); other_id++) {
|
||||
if (v_id == other_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector2D delta = positions[v_id] - positions[other_id];
|
||||
double distance = delta.norm();
|
||||
// TODO: handle distance == 0.0
|
||||
|
||||
// > 1000.0: not worth computing
|
||||
if (distance > 1000.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double repulsion = k_squared_ / distance;
|
||||
|
||||
mvmts_[v_id] += delta / distance * repulsion;
|
||||
mvmts_[other_id] -= delta / distance * repulsion;
|
||||
}
|
||||
|
||||
// Attraction force between edges
|
||||
for (vertex_id_t adj_id : g_[v_id]) {
|
||||
if (adj_id > v_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector2D delta = positions[v_id] - positions[adj_id];
|
||||
double distance = delta.norm();
|
||||
if (distance == 0.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double attraction = distance * distance / k_;
|
||||
|
||||
mvmts_[v_id] -= delta / distance * attraction;
|
||||
mvmts_[adj_id] += delta / distance * attraction;
|
||||
}
|
||||
}
|
||||
|
||||
// Max movement capped by current temperature
|
||||
for (vertex_id_t v_id = 0; v_id < g_.size(); v_id++) {
|
||||
double mvmt_norm = mvmts_[v_id].norm();
|
||||
// < 1.0: not worth computing
|
||||
if (mvmt_norm < 1.0) {
|
||||
continue;
|
||||
}
|
||||
double capped_mvmt_norm = std::min(mvmt_norm, temp_);
|
||||
Vector2D capped_mvmt = mvmts_[v_id] / mvmt_norm * capped_mvmt_norm;
|
||||
|
||||
positions[v_id] += capped_mvmt;
|
||||
}
|
||||
|
||||
// Cool down fast until we reach 1.5, then stay at low temperature
|
||||
if (temp_ > 1.5) {
|
||||
temp_ *= 0.85;
|
||||
} else {
|
||||
temp_ = 1.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "nodesoup.hpp"
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace nodesoup {
|
||||
class FruchtermanReingold {
|
||||
public:
|
||||
FruchtermanReingold(const adj_list_t& g, double k = 15.0);
|
||||
void operator()(std::vector<Point2D>& positions);
|
||||
|
||||
private:
|
||||
const adj_list_t& g_;
|
||||
const double k_;
|
||||
const double k_squared_;
|
||||
double temp_;
|
||||
std::vector<std::pair<vertex_id_t, vertex_id_t>> edges_;
|
||||
std::vector<Vector2D> mvmts_;
|
||||
};
|
||||
}
|
||||
188
Sapfor/_src/VisualizerCalls/graphLayout/kamada_kawai.cpp
Normal file
188
Sapfor/_src/VisualizerCalls/graphLayout/kamada_kawai.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#include "algebra.hpp"
|
||||
#include "kamada_kawai.hpp"
|
||||
|
||||
namespace nodesoup {
|
||||
|
||||
using std::vector;
|
||||
|
||||
|
||||
KamadaKawai::KamadaKawai(const adj_list_t& g, double k, double energy_threshold)
|
||||
: g_(g)
|
||||
, energy_threshold_(energy_threshold) {
|
||||
vector<vector<vertex_id_t>> distances = floyd_warshall_(g_);
|
||||
|
||||
// find biggest distance
|
||||
size_t biggest_distance = 0;
|
||||
for (vertex_id_t v_id = 0; v_id < g_.size(); v_id++) {
|
||||
for (vertex_id_t other_id = 0; other_id < g_.size(); other_id++) {
|
||||
if (distances[v_id][other_id] > biggest_distance) {
|
||||
biggest_distance = distances[v_id][other_id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ideal length for all edges. we don't really care, the layout is going to be scaled.
|
||||
// Let's chose 1.0 as the initial positions will be on a 1.0 radius circle, so we're
|
||||
// on the same order of magnitude
|
||||
double length = 1.0 / biggest_distance;
|
||||
|
||||
// init springs lengths and strengths matrices
|
||||
for (vertex_id_t v_id = 0; v_id < g_.size(); v_id++) {
|
||||
vector<Spring> v_springs;
|
||||
|
||||
for (vertex_id_t other_id = 0; other_id < g_.size(); other_id++) {
|
||||
Spring spring;
|
||||
if (v_id == other_id) {
|
||||
spring.length = 0.0;
|
||||
spring.strength = 0.0;
|
||||
} else {
|
||||
size_t distance = distances[v_id][other_id];
|
||||
spring.length = distance * length;
|
||||
spring.strength = k / (distance * distance);
|
||||
}
|
||||
|
||||
v_springs.push_back(spring);
|
||||
}
|
||||
springs_.push_back(v_springs);
|
||||
}
|
||||
}
|
||||
|
||||
vector<vector<vertex_id_t>> KamadaKawai::floyd_warshall_(const adj_list_t& g) {
|
||||
// build adjacency matrix (infinity = no edge, 1 = edge)
|
||||
unsigned int infinity = std::numeric_limits<unsigned int>::max() / 2;
|
||||
vector<vector<vertex_id_t>> distances(g.size(), vector<vertex_id_t>(g.size(), infinity));
|
||||
|
||||
for (vertex_id_t v_id = 0; v_id < g.size(); v_id++) {
|
||||
distances[v_id][v_id] = 0;
|
||||
for (vertex_id_t adj_id : g[v_id]) {
|
||||
if (adj_id > v_id) {
|
||||
distances[v_id][adj_id] = 1;
|
||||
distances[adj_id][v_id] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// floyd warshall itself, find length of shortest path for each pair of vertices
|
||||
for (vertex_id_t k = 0; k < g.size(); k++) {
|
||||
for (vertex_id_t i = 0; i < g.size(); i++) {
|
||||
for (vertex_id_t j = 0; j < g.size(); j++) {
|
||||
distances[i][j] = std::min(distances[i][j], distances[i][k] + distances[k][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distances;
|
||||
}
|
||||
|
||||
#define MAX_VERTEX_ITERS_COUNT 50
|
||||
#define MAX_STEADY_ENERGY_ITERS_COUNT 50
|
||||
|
||||
/**
|
||||
Reduce the energy of the next vertex with most energy until all the vertices have
|
||||
a energy below energy_threshold
|
||||
*/
|
||||
void KamadaKawai::operator()(vector<Point2D>& positions) const {
|
||||
vertex_id_t v_id;
|
||||
unsigned int steady_energy_count = 0;
|
||||
double max_vertex_energy = find_max_vertex_energy_(positions, v_id);
|
||||
|
||||
while (max_vertex_energy > energy_threshold_ && steady_energy_count < MAX_STEADY_ENERGY_ITERS_COUNT) {
|
||||
// move vertex step by step until its energy goes below threshold
|
||||
// (apparently this is equivalent to the newton raphson method)
|
||||
unsigned int vertex_count = 0;
|
||||
do {
|
||||
positions[v_id] = compute_next_vertex_position_(v_id, positions);
|
||||
vertex_count++;
|
||||
} while (compute_vertex_energy_(v_id, positions) > energy_threshold_ && vertex_count < MAX_VERTEX_ITERS_COUNT);
|
||||
|
||||
double max_vertex_energy_prev = max_vertex_energy;
|
||||
max_vertex_energy = find_max_vertex_energy_(positions, v_id);
|
||||
if (std::abs(max_vertex_energy - max_vertex_energy_prev) < 1e-20) {
|
||||
steady_energy_count++;
|
||||
} else {
|
||||
steady_energy_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Find @p max_energy_v_id with the most potential energy and @return its energy
|
||||
// https://gist.github.com/terakun/b7eff90c889c1485898ec9256ca9f91d
|
||||
*/
|
||||
double KamadaKawai::find_max_vertex_energy_(const vector<Point2D>& positions, vertex_id_t& max_energy_v_id) const {
|
||||
double max_energy = -1.0;
|
||||
for (vertex_id_t v_id = 0; v_id < g_.size(); v_id++) {
|
||||
double energy = compute_vertex_energy_(v_id, positions);
|
||||
if (energy > max_energy) {
|
||||
max_energy_v_id = v_id;
|
||||
max_energy = energy;
|
||||
}
|
||||
}
|
||||
assert(max_energy != -1.0);
|
||||
return max_energy;
|
||||
}
|
||||
|
||||
/** @return the potential energies of springs between @p v_id and all other vertices */
|
||||
double KamadaKawai::compute_vertex_energy_(vertex_id_t v_id, const vector<Point2D>& positions) const {
|
||||
double x_energy = 0.0;
|
||||
double y_energy = 0.0;
|
||||
|
||||
for (vertex_id_t other_id = 0; other_id < g_.size(); other_id++) {
|
||||
if (v_id == other_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector2D delta = positions[v_id] - positions[other_id];
|
||||
double distance = delta.norm();
|
||||
|
||||
// delta * k * (1 - l / distance)
|
||||
Spring spring = springs_[v_id][other_id];
|
||||
x_energy += delta.dx * spring.strength * (1.0 - spring.length / distance);
|
||||
y_energy += delta.dy * spring.strength * (1.0 - spring.length / distance);
|
||||
}
|
||||
|
||||
return sqrt(x_energy * x_energy + y_energy * y_energy);
|
||||
}
|
||||
|
||||
/**
|
||||
@returns next position for @param v_id reducing its potential energy, ie the energy in the whole graph
|
||||
caused by its position.
|
||||
The position's delta depends on K (TODO bigger K = faster?).
|
||||
This is the complicated part of the algorithm.
|
||||
*/
|
||||
Point2D KamadaKawai::compute_next_vertex_position_(vertex_id_t v_id, const vector<Point2D>& positions) const {
|
||||
double xx_energy = 0.0, xy_energy = 0.0, yx_energy = 0.0, yy_energy = 0.0;
|
||||
double x_energy = 0.0, y_energy = 0.0;
|
||||
|
||||
for (vertex_id_t other_id = 0; other_id < g_.size(); other_id++) {
|
||||
if (v_id == other_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector2D delta = positions[v_id] - positions[other_id];
|
||||
double distance = delta.norm();
|
||||
double cubed_distance = distance * distance * distance;
|
||||
|
||||
Spring spring = springs_[v_id][other_id];
|
||||
|
||||
x_energy += delta.dx * spring.strength * (1.0 - spring.length / distance);
|
||||
y_energy += delta.dy * spring.strength * (1.0 - spring.length / distance);
|
||||
xy_energy += spring.strength * spring.length * delta.dx * delta.dy / cubed_distance;
|
||||
xx_energy += spring.strength * (1.0 - spring.length * delta.dy * delta.dy / cubed_distance);
|
||||
yy_energy += spring.strength * (1.0 - spring.length * delta.dx * delta.dx / cubed_distance);
|
||||
}
|
||||
yx_energy = xy_energy;
|
||||
|
||||
Point2D position = positions[v_id];
|
||||
double denom = xx_energy * yy_energy - xy_energy * yx_energy;
|
||||
position.x += (xy_energy * y_energy - yy_energy * x_energy) / denom;
|
||||
position.y += (xy_energy * x_energy - xx_energy * y_energy) / denom;
|
||||
|
||||
return position;
|
||||
}
|
||||
}
|
||||
30
Sapfor/_src/VisualizerCalls/graphLayout/kamada_kawai.hpp
Normal file
30
Sapfor/_src/VisualizerCalls/graphLayout/kamada_kawai.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include "nodesoup.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace nodesoup {
|
||||
// https://gist.github.com/terakun/b7eff90c889c1485898ec9256ca9f91d
|
||||
// https://graphsharp.codeplex.com/SourceControl/latest#Source/Graph#/Algorithms/Layout/Simple/FDP/KKLayoutAlgorithm.cs
|
||||
class KamadaKawai {
|
||||
public:
|
||||
struct Spring {
|
||||
double length;
|
||||
double strength;
|
||||
};
|
||||
|
||||
KamadaKawai(const adj_list_t& g, double k = 300.0, double energy_threshold = 1e-2);
|
||||
void operator()(std::vector<Point2D>& positions) const;
|
||||
|
||||
private:
|
||||
const adj_list_t& g_;
|
||||
const double energy_threshold_;
|
||||
std::vector<std::vector<Spring>> springs_;
|
||||
|
||||
static std::vector<std::vector<vertex_id_t>> floyd_warshall_(const adj_list_t& g);
|
||||
// p m
|
||||
double find_max_vertex_energy_(const std::vector<Point2D>& positions, vertex_id_t& max_energy_v_id) const;
|
||||
// delta m
|
||||
double compute_vertex_energy_(vertex_id_t v_id, const std::vector<Point2D>& positions) const;
|
||||
Point2D compute_next_vertex_position_(vertex_id_t v_id, const std::vector<Point2D>& positions) const;
|
||||
};
|
||||
}
|
||||
68
Sapfor/_src/VisualizerCalls/graphLayout/layout.cpp
Normal file
68
Sapfor/_src/VisualizerCalls/graphLayout/layout.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "layout.hpp"
|
||||
#include "algebra.hpp"
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
namespace nodesoup {
|
||||
|
||||
using std::vector;
|
||||
|
||||
void circle(const adj_list_t& g, vector<Point2D>& positions) {
|
||||
const double pi = 3.14159265358979323846;
|
||||
double angle = 2.0 * pi / g.size();
|
||||
for (vertex_id_t v_id = 0; v_id < g.size(); v_id++) {
|
||||
positions[v_id].x = cos(v_id * angle);
|
||||
positions[v_id].y = sin(v_id * angle);
|
||||
}
|
||||
}
|
||||
|
||||
void center_and_scale(const adj_list_t& g, unsigned int width, unsigned int height, vector<Point2D>& positions) {
|
||||
// find current dimensions
|
||||
double x_min = std::numeric_limits<double>::max();
|
||||
double x_max = std::numeric_limits<double>::lowest();
|
||||
double y_min = std::numeric_limits<double>::max();
|
||||
double y_max = std::numeric_limits<double>::lowest();
|
||||
|
||||
for (vertex_id_t v_id = 0; v_id < g.size(); v_id++) {
|
||||
if (positions[v_id].x < x_min)
|
||||
x_min = positions[v_id].x;
|
||||
if (positions[v_id].x > x_max)
|
||||
x_max = positions[v_id].x;
|
||||
if (positions[v_id].y < y_min)
|
||||
y_min = positions[v_id].y;
|
||||
if (positions[v_id].y > y_max)
|
||||
y_max = positions[v_id].y;
|
||||
}
|
||||
|
||||
double cur_width = x_max - x_min;
|
||||
double cur_height = y_max - y_min;
|
||||
|
||||
// compute scale factor (0.9: keep some margin)
|
||||
double x_scale = (cur_width > 0) ? width / cur_width : width;
|
||||
double y_scale = (cur_height > 0) ? height / cur_height : height;
|
||||
Vector2D scale = { x_scale, y_scale };
|
||||
|
||||
// compute offset and apply it to every position
|
||||
Vector2D center = { x_max + x_min, y_max + y_min };
|
||||
Vector2D offset = (center / 2.0) * scale;
|
||||
|
||||
double shiftMinX = std::numeric_limits<double>::max();
|
||||
double shiftMinY = std::numeric_limits<double>::max();
|
||||
|
||||
for (vertex_id_t v_id = 0; v_id < g.size(); v_id++)
|
||||
{
|
||||
positions[v_id] = (Point2D)((Vector2D)positions[v_id] * scale - offset);
|
||||
shiftMinX = std::min(shiftMinX, positions[v_id].x);
|
||||
shiftMinY = std::min(shiftMinY, positions[v_id].y);
|
||||
}
|
||||
|
||||
shiftMinX = abs(shiftMinX) + 50;
|
||||
shiftMinY = abs(shiftMinY) + 50;
|
||||
|
||||
for (auto& pos : positions)
|
||||
{
|
||||
pos.x += shiftMinX;
|
||||
pos.y += shiftMinY;
|
||||
}
|
||||
}
|
||||
}
|
||||
10
Sapfor/_src/VisualizerCalls/graphLayout/layout.hpp
Normal file
10
Sapfor/_src/VisualizerCalls/graphLayout/layout.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "nodesoup.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace nodesoup {
|
||||
/** Distribute vertices equally on a 1.0 radius circle */
|
||||
void circle(const adj_list_t& g, std::vector<Point2D>& positions);
|
||||
/** Center and scale vertices so the graph fits on a canvas of given dimensions */
|
||||
void center_and_scale(const adj_list_t& g, unsigned int width, unsigned int height, std::vector<Point2D>& positions);
|
||||
}
|
||||
64
Sapfor/_src/VisualizerCalls/graphLayout/nodesoup.cpp
Normal file
64
Sapfor/_src/VisualizerCalls/graphLayout/nodesoup.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "nodesoup.hpp"
|
||||
#include "fruchterman_reingold.hpp"
|
||||
#include "kamada_kawai.hpp"
|
||||
#include "layout.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace nodesoup {
|
||||
|
||||
using std::vector;
|
||||
|
||||
vector<Point2D> fruchterman_reingold(
|
||||
const adj_list_t& g,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int iters_count,
|
||||
double k,
|
||||
iter_callback_t iter_cb) {
|
||||
vector<Point2D> positions(g.size());
|
||||
// Initial layout on a circle
|
||||
circle(g, positions);
|
||||
|
||||
FruchtermanReingold fr(g, k);
|
||||
for (unsigned int i = 0; i < iters_count; i++) {
|
||||
fr(positions);
|
||||
|
||||
if (iter_cb != nullptr) {
|
||||
vector<Point2D> scaled_positions = positions;
|
||||
center_and_scale(g, width, height, scaled_positions);
|
||||
iter_cb(scaled_positions, i);
|
||||
}
|
||||
}
|
||||
|
||||
center_and_scale(g, width, height, positions);
|
||||
return positions;
|
||||
}
|
||||
|
||||
vector<Point2D> kamada_kawai(
|
||||
const adj_list_t& g,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
double k,
|
||||
double energy_threshold) {
|
||||
vector<Point2D> positions(g.size());
|
||||
// Initial layout on a circle
|
||||
circle(g, positions);
|
||||
KamadaKawai kk(g, k, energy_threshold);
|
||||
kk(positions);
|
||||
center_and_scale(g, width, height, positions);
|
||||
|
||||
return positions;
|
||||
}
|
||||
|
||||
vector<double> size_radiuses(const adj_list_t& g, double min_radius, double k) {
|
||||
vector<double> radiuses;
|
||||
radiuses.reserve(g.size());
|
||||
for (vertex_id_t v_id = 0; v_id < g.size(); v_id++) {
|
||||
double delta = log2(k * (double) g[v_id].size() / g.size());
|
||||
double radius = min_radius + std::max(0.0, delta);
|
||||
radiuses.push_back(radius);
|
||||
}
|
||||
return radiuses;
|
||||
}
|
||||
}
|
||||
69
Sapfor/_src/VisualizerCalls/graphLayout/nodesoup.hpp
Normal file
69
Sapfor/_src/VisualizerCalls/graphLayout/nodesoup.hpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
namespace nodesoup {
|
||||
|
||||
/** Simple adjaceny list graph structure */
|
||||
|
||||
using vertex_id_t = std::size_t;
|
||||
using adj_list_t = std::vector<std::vector<vertex_id_t>>;
|
||||
|
||||
/** Algebra types */
|
||||
|
||||
struct Vector2D;
|
||||
|
||||
struct Point2D {
|
||||
double x;
|
||||
double y;
|
||||
|
||||
explicit operator Vector2D() const;
|
||||
Point2D& operator+=(const Vector2D& vector);
|
||||
Point2D& operator-=(const Vector2D& vector);
|
||||
std::pair<int, int> toPair() { return std::make_pair((int)x, (int)y); }
|
||||
};
|
||||
|
||||
struct Vector2D {
|
||||
double dx;
|
||||
double dy;
|
||||
|
||||
double norm() const {
|
||||
return sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
explicit operator Point2D() const;
|
||||
Vector2D& operator+=(const Vector2D& other);
|
||||
Vector2D& operator-=(const Vector2D& other);
|
||||
Vector2D& operator*=(double scalar);
|
||||
Vector2D& operator/=(double scalar);
|
||||
Vector2D& operator*(const Vector2D& other);
|
||||
};
|
||||
|
||||
/** Main library functions */
|
||||
|
||||
using iter_callback_t = std::function<void(const std::vector<Point2D>&, int)>;
|
||||
|
||||
/**
|
||||
Applies the Freuchterman Reingold algorithm to layout graph @p in a frame of dimensions
|
||||
@p width and @p height, in @p iter-count iterations
|
||||
*/
|
||||
std::vector<Point2D> fruchterman_reingold(
|
||||
const adj_list_t& g,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int iters_count = 300,
|
||||
double k = 15.0,
|
||||
iter_callback_t iter_cb = nullptr);
|
||||
|
||||
std::vector<Point2D> kamada_kawai(
|
||||
const adj_list_t& g,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
double k = 300.0,
|
||||
double energy_threshold = 1e-2);
|
||||
|
||||
/** Assigns diameters to vertices based on their degree */
|
||||
std::vector<double> size_radiuses(const adj_list_t& g, double min_radius = 4.0, double k = 300.0);
|
||||
}
|
||||
Reference in New Issue
Block a user