0

I have a Django application and I'm using pythonOCC package in it. I have to display the 3D .stl, .stp, .igs files in my template. I have tried to use render() function which in x3dom_renderer.py file in the package.

Here is my view:

from OCC.Extend.DataExchange import read_step_file
from OCC.Display.WebGl import x3dom_renderer
from OCC.Core.BRep import BRep_Builder
from OCC.Core.TopoDS import TopoDS_Shape
from OCC.Core.BRepTools import breptools_Read

def index(request):
    shape = read_step_file('test.stp')
    my_renderer = x3dom_renderer.X3DomRenderer()
    my_renderer.DisplayShape(shape)
    my_renderer.render()
    return render(request, 'index.html')

When I call the render() function, the following outputs appear on my vscode console and since flask app created by pythonocc instead of django starts running in localhost, my index.html is never rendered.

The output when I call the render function:

 **  Model Complete Check List  **
Check:1 -- Entity (n0:id) 5:#14   Type:CURVE_STYLE
Parameter n0.2 (curve_font) not an Entity
Check:2 -- Entity (n0:id) 6:#15   Type:CURVE_STYLE
Parameter n0.2 (curve_font) not an Entity
Check:3 -- Entity (n0:id) 7:#16   Type:CURVE_STYLE
Parameter n0.2 (curve_font) not an Entity
Check:4 -- Entity (n0:id) 8:#17   Type:CURVE_STYLE
Parameter n0.2 (curve_font) not an Entity
Check:5 -- Entity (n0:id) 9:#18   Type:CURVE_STYLE
Parameter n0.2 (curve_font) not an Entity
Check:6 -- Entity (n0:id) 10:#19   Type:CURVE_STYLE
Parameter n0.2 (curve_font) not an Entity
## x3dom webgl renderer - render axes/planes : True - axes/plane zoom factor : 1
| meshing shapes... 100%
## Serving C:\Users\imgea\AppData\Local\Temp\tmppopa5opx
## using Flask
## Open your webbrowser at the URL: http://localhost:8080

As you see in this x3dom_renderer.py https://github.com/tpaviot/pythonocc-core/blob/master/src/Display/WebGl/x3dom_renderer.py, the html file is created in this python file and is shaped according to the image which I sent. How can I use this renderer in my Django template? Could you give any suggestions?

Aslı Kök
  • 616
  • 8
  • 19

2 Answers2

1

The HTML consists of a few variables which you might not all need. Probably the <head> section you will create yourself. The JavaScript parts are useful to insert in your template. A relatively easy way to do this is to add a context processor, see this section of the Django documentation. Basically you define a function that gives extra variables to templates you are rendering.

In my_app/context_processors.py. Note that because we trust the HTML, we add mark_safe to it, to prevent templates escaping the HTML:

from Display.WebGl.three_js_renderer import BODY_PART1, BODY_PART2
from django.utils.safestring import mark_safe

def threejs_context(request):
  return {
    'threejs_body_part1':  mark_safe(BODY_PART1),
    'threejs_body_part2': mark_safe(BODY_PART2),
  }

In your project's settings.py:

TEMPLATES = [
  {
    ...
    'context_processors': [
      ...
      'my_app.context_processors.threejs_context',
    ],
    ...
  }
]

Now in your templates, you can use the defined variables to insert the HTML in your context:

{{ threejs_body_part1 }}
{{ threejs_body_part1 }}
Lucas Moeskops
  • 5,445
  • 3
  • 28
  • 42
  • you're right but when I call the render( ) function, it's calling a function into it which it's name is generate_html_file( ) and the HTML file that we try to add as context_processors is filling according to the image info with that function. So I have to call the generate_html_file( ) first. However, the generate_html_file( ) function is write the HTML codes to a tempfile. So I need to add the body part from that tempfile. I have tried to override the threejs_renderer.py file but I couldn't. – Aslı Kök Sep 03 '20 at 10:39
  • Ah I see that now indeed. So would you want to just render the whole HTML code as a single template output, or do you want to use part of that HTML code included on an existing Django template? – Lucas Moeskops Sep 03 '20 at 10:49
  • I want to use the whole HTML in a – Aslı Kök Sep 03 '20 at 10:53
  • I see what you need now, so I added a different answer. – Lucas Moeskops Sep 03 '20 at 11:39
0

The render function starts its own server so I think this one should not be called. It might be useful to extend the Renderer class, to add the functions to it that we miss. In this case an option to render to string, so we can use the output.

from OCC.Extend.DataExchange import read_step_file
from OCC.Display.WebGl import x3dom_renderer
from OCC.Core.BRep import BRep_Builder
from OCC.Core.TopoDS import TopoDS_Shape
from OCC.Core.BRepTools import breptools_Read
from django.http.response import HttpResponse


class CustomX3DomRenderer(x3dom_renderer.X3DomRenderer):
    def render_to_string(self):
        # N.B. Writing the html file to disk isn't really needed; you 
        # could also build the string directly without writing it
        # to disk
        self.generate_html_file(self._axes_plane, self._axes_plane_zoom_factor)
        return open(self._html_filename, 'r').read()


def index(request):
    shape = read_step_file('test.stp')
    my_renderer = CustomX3DomRenderer()
    my_renderer.DisplayShape(shape)
    return HttpResponse(my_renderer.render_to_string())
Lucas Moeskops
  • 5,445
  • 3
  • 28
  • 42
  • yes that makes sense. But I have tried to override the renderer.py file but in cloud, the pythonocc-core library is installed automatically with a config file. Then I have tried to add just the renderer.py file to my root directory of my project but now, I'm getting `AttributeError: 'ShapeTesselator' object has no attribute 'ExportShapeToX3DTriangleSet'` – Aslı Kök Sep 03 '20 at 11:43
  • You don't need to change the location or the contents of the library file I think. You can just override the classes in your own files like I did in the example for X3DomRenderer. – Lucas Moeskops Sep 03 '20 at 11:47
  • Oh sorry, I missed there. I'm trying. – Aslı Kök Sep 03 '20 at 11:48
  • It works, the viewer is opening but the image isn't shown. I guess it's because of the .x3d file. The renderer.py file creates a file for example which it's name is `shp63c6c9ed8a6f41a6a80a5169cc85a4ac.x3d` and it uses the file in template as ``. The template cannot find this file. – Aslı Kök Sep 03 '20 at 11:59
  • Ah yes.. those are also saved somewhere. Do you see the files saved in a certain directory? – Lucas Moeskops Sep 03 '20 at 12:01
  • Yes, in `C:\Users\imgea\AppData\Local\Temp\` which it cames from self._path – Aslı Kök Sep 03 '20 at 12:33
  • Ah, so you can specify your own path to the custom renderer class with `path=my_path`, but it doesn't add a prefix to the urls it creates unfortunately. Ideally you want to customize it so that it adds prefixes like '/media/my_file.x3d'. Then you can add the files to your settings.MEDIA_ROOT path: e.g. `CustomX3DomRenderer(path=settings.MEDIA_ROOT)`. – Lucas Moeskops Sep 03 '20 at 12:49
  • Actually, I'm already using s3 bucket and I will get these images from there. I'm using tempfile while reading them on s3 bucket, too. Is it still necessary? And why it cannot find the file i couldn't understand. – Aslı Kök Sep 03 '20 at 12:56
  • self._path is true but i guess it's looking for the file in `/myapp/myview/shp21db216bb49a4882aaa9ebcb5d7f34af.x3d`, i don't understand why. Because the error is `Not Found: /file/occview/shp21db216bb49a4882aaa9ebcb5d7f34af.x3d` – Aslı Kök Sep 03 '20 at 13:12