GithubHelp home page GithubHelp logo

serg-norseman / arbor Goto Github PK

View Code? Open in Web Editor NEW
3.0 5.0 2.0 556 KB

ArborGVT - the graph vizualization toolkit. Implementations: C#, Java, C++.

License: GNU Lesser General Public License v3.0

C# 6.65% C++ 69.95% C 0.56% Java 7.56% Makefile 15.22% Batchfile 0.05%
graph-vizualization-toolkit graph

arbor's Introduction

Arbor

ArborGVT is the graph vizualization toolkit.

This is a fork of the `Arbor.js' project (Copyright 2011 Samizdat Drafting Co.).

Ported to C# language from JavaScript in March-April 2012 (Copyright 2012 by Serg V. Zhdanovskih).
Ported to Java language from C# in January 2016 (Copyright 2016 by Serg V. Zhdanovskih).
Ported to C++ (Windows native binary) in January-March 2016 (Copyright 2016 by Serg V. Zhdanovskih, @ruslangaripov).

arbor's People

Contributors

ruslangaripov avatar serg-norseman avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

arbor's Issues

Inherit the algorithms

It is necessary to move the algorithms from C# version of code into C++ version, uniting tickets #8 and #9 ๐Ÿƒ
Enhanced performance is welcomed as always.

`ArborGVT::Branch` class: initializing of `Pt` member

Currently ArborGVT::Branch::Pt member is initialized with QNaN:

        public Branch(ArborPoint origin, ArborPoint size)
        {
            . . .
            this.Pt = ArborPoint.Null;
        }

where

namespace ArborGVT
{
    public struct ArborPoint
    {
        public static readonly ArborPoint Null = new ArborPoint(double.NaN, double.NaN);
        . . .
    }
}

and double.NaN is QNaN (at least in .NET Framework 4.6).

Next, the following code is used inside Barnes Hut simulation initialization:

Branch f = . . .;
. . .
if (!f.Pt.isNull())
{
    f.Pt = f.Pt.add(h.Pt.mul(m));
}
else
{
    f.Pt = h.Pt.mul(m);
}

where:

namespace ArborGVT
{
    public struct ArborPoint
    {
        . . .
        public bool isNull()
        {
            return (double.IsNaN(this.X) && double.IsNaN(this.Y));
        }
        . . .
    }
}

The code above with if (!f.Pt.isNull()) is the only place where f.Pt is checked this way.

Therefore, had we initialized ArborGVT::Branch::Pt with zeros, we can omit such checking.

Data model

It is necessary to create a program data model for storing graph (its vertices and edges) meeting the following requirements:

  • Graph may be mixed,
  • Graph allows two or more edges that connect the same two vertices (multigraph) with enabled loops,
  • Graph allows edges with only one end (half-edges).

Graph (mathematics)

Prepare rendering (phase #1)

The library must:

  • Exports C++ class or function (the first is more preferable) that wraps a HWND created by a dedicated GUI thread. The HWND is a place where the graph is rendered. Client of the HWND controls the window styles (general and extended). Client of the HWND controls the window with Windows API calls. Client ain't aware of the GUI thread owning the HWND; the library controls the thread by itself.
  • The class or another function must give ability to set initial data or add new data to the graph (too early to implement in this ticket).

View model

It is necessary to create a program view model that renders data model from ticket #8 meeting the following requirements:

  • The model renders on HWND surface with Direct2D 1.1,
  • The model is WAM ready.

Move graph settings to a dedicated class

To make the ARBOR graph class declaration more clear move all static constexpr constants to new base class.

I'm talking about this:

{
    . . .
    static constexpr float m_stiffness = 250.0f;
#if defined(__ICL)
    static constexpr float m_repulsion = 10000.0f;
#else
    static constexpr float m_repulsion = 10'000.0f;
#endif
    static constexpr float m_friction = 0.1f;
    static constexpr float m_animationStep = 0.04f;
    static constexpr float m_timeSlice = 0.01f;
    static constexpr float m_energyThreshold = 0.7f;
    static constexpr float m_theta = 0.4f;
    static constexpr bool m_gravity = false;
    static constexpr bool m_autoStop = false;
    . . .
}

Create projects templates

Create two empty projects templates (united by one VS 2015 solution): one for sample application (native Win32 desktop) and one for Windows native DLL library. The library will bring the target source code.

ArborGVT & SmartGraph

To find a way to perform the integration of the Arbor and SmartGraph. Thus it is crucial to maintain the possibility of their independence from each other. The big question is how to do it...

Hungarian notation

Here and there I'm using Hungarian notation in the code derived from my old projects where it was a norm. ๐Ÿชฒ Hungarian notation is evil 'cos it encodes type information in names. Therefore this notation must be removed from the code in this project. ๐Ÿ‘ฟ

System.Drawing.PointF structure

โ“ What about inheriting ArborGVT::ArborPoint class from System.Drawing.PointF? Or you need C# struct and not its class? Or Single type doesn't have enough precision?

Store mass as vector

Currently my C++ implementation stores mass property as simple single precision floating point type (float) value, almost just like the original C# code does (it uses double precision type double).

Switching to a vectorized data can avoid multiple usage of MOVAPS + SHUFPS pair.

To improve code performance the following classes must use __m128 when operate with mass:

  • vertex (vertex.h),
  • branch (bhutquad.h),
  • particle (bhutquad.h; this class uses mass via graph vertex).

Move constexpr struct data member initialization back, to header file

๐Ÿ› Because of a bug in MSVC 2015 before Update 2 I couldn't do this:

struct foo
{
    static constexpr D2D1_SIZE_F m_member = {10.0f, 20.0f};
}

I had to do such member definition in a 'cpp' file:

D2D1_SIZE_F foo::m_member = {10.0f, 20.0f};

After this has been fixed in MSVC 2015 Update 2, I can safely move this initialization back into header file.

I'm talking about graphwnd.h and graphwnd.cpp files.

Graph vertices are drawn too small

Sometimes, when sample application starts, all vertices in the graph are rendered as a circle (not an ellipse) with one letter and "..." inside.

This is because sometimes HWND, where the graph is rendered, is shown before HWND get resized. And because a vertex's text layout object depends on size of the HWND (maximum width and height of layout depend on size of owner window), a text layout gets very small initial size. Based on text layout size a vertex area becomes a circle.

Roll down of code and micro-optimizations

  1. Roll down of function ArborNode.applyForce() increase speed of run BarnesHutTree.applyForces() by 30%.
  2. If check arguments of f.Enqueue(branch.Q[QNe]); in BarnesHutTree.applyForces() before Enqueue() - it increase speed by 5-10%.
  3. Roll down of function ArborPoint.normalize() yet increase speed by 3-5%.

Don't know if this makes sense.

Prepare rendering (phase #2)

The sample application uses the target library to get HWND and shows the HWND as a child window. The child window must have fixed size while the top window of the application doesn't. Therefore it may have optional scroll bars (horizontal and/or vertical).

FPS indicator is scrolled with window content

๐Ÿ› Enabled FPS indicator is scrolled with the graph window content. But it should always remain in the top left corner of the window, regardless of scrolling. Therefore FPS stat always overlaps graph elements.

Build with SHOW_FPS defined to enable FPS statistics

Operator overloading [proposal]

While I'm getting familiar with general algorithms implemented in C# code of ArborGVT, I found a stuff that I would have made if I had implemented this ๐Ÿ˜Š I'm talking about operators overloading in the ArborGVT::ArborPoint class.
I propose the following: to replace "math" methods (add, sub, mul and so on) with overloaded operators.
Yes, it's may be a stylistic preference and that's why this is just a proposal. But I really believe this will improve code readability โ˜บ๏ธ

Prefer `std::condition_variable` to `HANDLE`

Currently DLL library uses Windows event object to notify main application that DLL's window is ready.

Try to change it and use std::condition_variable instead of Windows native HANDLE.

This can hit overall application performance at "startup", but gives more independence from Windows platform.

'ArborGVT::ArborSystem::updatePosition' implementation

Given

The following loop exists in the ArborGVT::ArborSystem::updatePosition method:

foreach (ArborNode v in fNodes)
{
    v.Pt = v.Pt.add(v.v.mul(q));
    . . .
    ArborPoint y = v.Pt;
    if (y.exploded()) continue;
    . . .
}

This is definition of the ArborGVT::ArborPoint::add method:

public ArborPoint add(ArborPoint a)
{
    return new ArborPoint(this.x + a.x, this.y + a.y);
}

And the following code is definition of the ArborGVT::ArborPoint::exploded method:

public bool exploded()
{
    return (double.IsNaN(this.x) || double.IsNaN(this.y));
}

The question

The first statement in the loop v.Pt = v.Pt.add(v.v.mul(q)) increments x and y data members of v.Pt by some value. Had value of x or y be `NaN', I believe the code throws an exception. Does it?

Therefore after that line we can state that v.Pt.x and v.Pt.y ain't NaN. Otherwise exception generated by the add method would break execution.

And then we emit if statement:

    . . .
    ArborPoint y = v.Pt;
    if (y.exploded()) continue;
    . . .

that checks if v.Pt.x or v.Pt.y is NaN. But we already have proved that this cannot be! So my question is: "why do we check that again"?

Refactoring

  1. Walk through the source code using ReSharper, to rename the part of variables and other names for compliance with conventions.
  2. To perform the standard VS code analysis.
  3. To check code metrics VS.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.