walkinside / sdk

Develop powerful desktop and web applications on top of Walkinside 3D engine
4 stars 4 forks source link

Loading a model and FRT from code #69

Open rkhala opened 5 years ago

rkhala commented 5 years ago

I want to develop a program that can pass certain parameters project name, FRT elements etc. and will open a walkinside instance and load this project and highlight the required FRT element and focus on it in the model.

The examples provided in viewerSDK do it through a plugin. This requires additional user interaction to use the plugin. I want to do it in a way that a click from my program will run the functionality as described above.

Please advise if this is feasible and suggest ideas/ supporting APIs to develop something like this.

Thanks in advance

griemens commented 4 years ago

Hi,

I have maybe found a way to achieve your requirement. Walkinside has a built in feature to interact with external applications through web. This is what we call the Walkinside http server. (For more information see manual and search for "Walkinside HTTP Server") Now this built in server does not have the API to load a project. So the idea would be to implement your own plugin in Walkinside to expose similar features.

And in your application you could do the following: Request through web url on localhost to open a project and jumpto a tag. => If response is server not available

Have implemented a http server to make some testing, and here is the code of the class.

    class WebServer
    {
        IVRViewerSdk SDKViewer = null;
        private HttpListener m_Listener = null;
        public WebServer(IVRViewerSdk viewer)
        {
            SDKViewer = viewer;
        }

        public void Start(int port)
        {
            if (!HttpListener.IsSupported)
            {
                throw new NotSupportedException("Needs Windows version with ttplistener support.");
            }

            m_Listener = new HttpListener();
            m_Listener.Prefixes.Add(string.Format("http://localhost:{0}/",port));

            m_Listener.Start();
            ThreadPool.QueueUserWorkItem(o =>
            {
                try
                {
                    while (m_Listener.IsListening)
                    {
                        ThreadPool.QueueUserWorkItem(c =>
                        {
                            var context = c as HttpListenerContext;
                            try
                            { 
                                string methodName = context.Request.Url.Segments[1].Replace("/", "");
                                if (methodName == "favicon.ico")
                                {
                                    context.Response.OutputStream.Close();
                                    return;
                                }

                                var method = this.GetType().GetMethod(methodName);
                                NameValueCollection query = context.Request.QueryString;

                                object[] @params = method.GetParameters()
                                                    .Select((p, i) => Convert.ChangeType(query[p.Name], p.ParameterType))
                                                    .ToArray();

                                object ret = method.Invoke(this, @params);

                                byte[] buffer = System.Text.Encoding.UTF8.GetBytes(ret.ToString());
                                HttpListenerResponse response = context.Response;
                                response.ContentLength64 = buffer.Length;
                                System.IO.Stream output = response.OutputStream;
                                output.Write(buffer, 0, buffer.Length);
                                output.Close();
                            }
                            catch(Exception ex)
                            {
                                Console.WriteLine(ex.Message);
                            }
                            finally
                            {
                                if (context != null)
                                {
                                    context.Response.OutputStream.Close();
                                }
                            }
                        }, m_Listener.GetContext());
                    }
                }
                catch (Exception)
                {
                }
            });
        }

        public void Stop()
        {
            m_Listener.Stop();
            m_Listener.Close();
            m_Listener = null;
        }

        public string OpenProjectAndSelect(string projectname, string tagname)
        {
            if (SDKViewer.UI.Control.InvokeRequired)
            {
                return (string)SDKViewer.UI.Control.Invoke(new Func<String>(() =>
                    { return this.OpenProjectAndSelect(projectname, tagname); }));
            }
            else
            {
                string error = null;
                bool? success = SDKViewer.ProjectManager.LoadProject(projectname, out error);
                if (error != null)
                {
                    if (string.Compare(error, "This project is already in use") != 0)
                        return "<HTML><BODY>" + DateTime.Now.ToShortTimeString() + "<BR>" + error + "</BODY></HTML>";
                    else
                        success = true;
                }
                if (success.Value)
                {
                    var branches = SDKViewer.ProjectManager.CurrentProject.BranchManager.GetBranchesByExactNames(new[] { tagname }).ToArray();
                    foreach (var branch in branches)
                    {
                        branch.Select();
                        SDKViewer.ProjectManager.CurrentProject.BranchManager.FlyToCurrentSelection(branch.Kind);
                        break;
                    }
                }
                return "<HTML><BODY>" + DateTime.Now.ToShortTimeString() + " : Loaded </BODY></HTML>";
            }
        }
    }

Now you can use this class as follows in your walkinside plugin, to start and stop this server.

class WIPlugin: IVRPlugin
{
...
        WebServer m_Server = null;
        public bool CreatePlugin(IVRViewerSdk viewer)
        {
            // Do initialisation of plugin instance.
            m_Server = new WebServer(viewer);
            m_Server.Start(8080);
            return true;
        }

        public bool DestroyPlugin(IVRViewerSdk viewer)
        {
            m_Server.Stop();
            return true;
        }
...
}

You can test the behavior now using a webrowser, and type in the address bar the following.

http://localhost:8080/OpenProjectAndSelect?projectname=C:\1.Demos\Stabilizer\Stabilizer.vrp&tagname=/PM1S1P16B

Providing an URL to an online Walkinside model works as well for projectname.

Hope this helps. If not let us know what is missing.

Kind regards