<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:Consolas;
        panose-1:2 11 6 9 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
pre
        {mso-style-priority:99;
        mso-style-link:"HTML Preformatted Char";
        margin:0in;
        font-size:10.0pt;
        font-family:"Courier New";}
span.HTMLPreformattedChar
        {mso-style-name:"HTML Preformatted Char";
        mso-style-priority:99;
        mso-style-link:"HTML Preformatted";
        font-family:Consolas;}
span.ansi-green-fg
        {mso-style-name:ansi-green-fg;}
span.ansi-cyan-fg
        {mso-style-name:ansi-cyan-fg;}
span.ansi-blue-fg
        {mso-style-name:ansi-blue-fg;}
span.ansi-green-intense-fg
        {mso-style-name:ansi-green-intense-fg;}
span.ansi-red-fg
        {mso-style-name:ansi-red-fg;}
span.EmailStyle26
        {mso-style-type:personal-reply;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-US" link="blue" vlink="purple" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal">Moritz:<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Thanks 1M for your close scrutiny and excellent examples.  I particularly like how your presentation of multiple criss-crossing point sources would likely not be discernable if only shown in 2D, and possibly even confusing as a movie portrayal. 
 User ability to navigate and inspect quickly revealed the nature of intersecting, tightly bound signal paths.  Cool!<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Your points regarding Python architecture of x3d.py are helpful.  Am meeting with our resident Python guru on Friday to discuss in detail.  Looks like your proposed bugfix will help.  In general, I think that first-class numpy scientific-stack
 compatibility is a high priority, and this will be our first chance to pursue that.  Am hopeful that we can first perform duck typing through the X3D type classes (SFVec3f, MFFloat, etc. etc.) and corresponding validation functions (Boolean and assertion). 
 At that point a little more experimentation will likely help us quickly decide whether further code generation is warranted throughout the individual fields of X3D.  It is further simple to perform corresponding upgrades to the stylesheet converter and all
 of the online examples.  Simple is good.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Your diagnosis of import and init issues is also welcome, as an unrepentant Java programmer I’ve always thought that approach useful but a bit gnarly.  No doubt we’ll ponder official guidance and various textbooks closely.  We might also
 find that simple screensharing reveals an easily fixed tangle… onward we go, one step at a time.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">We are only building and releasing one version of x3d.py so no worries about possible versionitis woes.  Package is pretty stable but internal patterns can easily evolve. We want to Do The Right Thing which means supporting the Python community,
 which uhh is measurable.  8)<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Documentation can always be improved and indeed can be a helpful confirmation of shared clarity and group understanding.  Please note any question marks or confounders as you go.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<p class="MsoNormal">Glad that x3d.py is working for you, we strive to be Pythonic!  Will follow up, looking forward to further progress together, good luck with your work.<o:p></o:p></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Courier New""><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Courier New"">all the best, Don<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Courier New"">-- <o:p>
</o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Courier New"">Don Brutzman  Naval Postgraduate School, Code USW/Br        brutzman@nps.edu<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Courier New"">Watkins 270,  MOVES Institute, Monterey CA 93943-5000 USA    +1.831.656.2149<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Courier New"">X3D graphics, virtual worlds, Navy robotics https://</span>
<span style="font-size:10.0pt;font-family:"Courier New"">faculty.nps.edu/brutzman<o:p></o:p></span></p>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div style="border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal"><b>From:</b> x3d-public <x3d-public-bounces@web3d.org> <b>On Behalf Of
</b>Hans Moritz Guenther<br>
<b>Sent:</b> Wednesday, February 9, 2022 8:23 AM<br>
<b>To:</b> x3d-public@web3d.org<br>
<b>Subject:</b> [x3d-public] A few suggestions from the Python API (x3d.py)<o:p></o:p></p>
</div>
</div>
<p>Hi,<o:p></o:p></p>
<p>I'm starting to use the x3d.py library to generate x3d output. I'm very much a Python programmer using what people call the "scientific stack" in Python (the libraries numpy, scipy, pandas, etc.) with very little experience in 3D visualization or web-programming.<o:p></o:p></p>
<p>I understand that you autogenerate the programming language API from the X3DOUM, but I do not know which, if any, of the comments generalize to the APIs in other programming languages or which ones are specific to the Python implementation in x3d.py.<o:p></o:p></p>
<p>For a little bit of background, I'm an astronomer and one of the things I do is ray-tracing of the designs for new space-based observatories. It is then very useful to have some form of output that allows me to put images of how the instrument looks and
 what path the photons take into presentations or on the web. As it turns out, X3D is a great format for that, see e.g.
<a href="https://nam10.safelinks.protection.outlook.com/?url=https%3A%2F%2Fspace.mit.edu%2Fhome%2Fguenther%2FARCUS%2F3Dview.html&data=04%7C01%7Cbrutzman%40nps.edu%7C2c7d4294f26747a1ac8308d9ebe89cde%7C6d936231a51740ea9199f7578963378e%7C0%7C0%7C637800209456879782%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=RRyCO0F1KB8HFPMxhcPAiyPcQsDSJS0OPUjl%2B2JhWYI%3D&reserved=0">
https://space.mit.edu/home/guenther/ARCUS/3Dview.html</a> In that past, I've generated the X3D output through a python package called mayavi (<a href="https://nam10.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdocs.enthought.com%2Fmayavi%2Fmayavi%2F&data=04%7C01%7Cbrutzman%40nps.edu%7C2c7d4294f26747a1ac8308d9ebe89cde%7C6d936231a51740ea9199f7578963378e%7C0%7C0%7C637800209456879782%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=4cq4pmXSaLHsQcBlO%2BeXsQBRSd5G6sgNa%2BW5ilD2pyU%3D&reserved=0">https://docs.enthought.com/mayavi/mayavi/</a>)
 but that is a rather heavy dependency for this very limited purpose. So, I'm trying to convert to use your x3d.py library instead.
<o:p></o:p></p>
<p>First, let me thank you for your effort to make x3d.py at all. In general it works great!<o:p></o:p></p>
<p>I'd like to mention a few glitches I've run into so far:<o:p></o:p></p>
<p>- IndexTriangleSet: Coordinates are given as a list of tuples [(x1, y1, z1), (x2, y2, y3), ...]. I think that makes sense. It orders stuff in a natural way and is easy to understand. However, the index needs to be given as a flat list [ind11, ind12, ind13,
 ind21, ind22, ind23, ...]. Since there are three indices per triangle, I think the same list of tuples as for the coordinates would make more sense [( ind11, ind12, ind13), (ind21, ind22, ind23) ...]. I've not checked if the same thought applied to e.g. the
 IndexedFaceSet etc. I'm still pretty new to this and can't claim to know all relevant nodes.<o:p></o:p></p>
<p>- the __init__.py file. The file is present, but not correct. It lists all the classes in __all__ but does not actually import them. Thus, that can't actually be used.<o:p></o:p></p>
<p>I<span style="font-family:"Courier New"">n [1]: import x3d<br>
<br>
In [2]: x3d.IndexedTriangleSet<br>
---------------------------------------------------------------------------<br>
AttributeError                            Traceback (most recent call last)<br>
<ipython-input-2-93a98d5f0414> in <module><br>
----> 1 x3d.IndexedTriangleSet</span><o:p></o:p></p>
<p>Instead, I need to use "x3d.x3d". That's of course possible but a little cumbersome.<o:p></o:p></p>
<p><span style="font-family:"Courier New"">In [4]: import x3d.x3d<br>
x3d.py package loaded, have fun with X3D Graphics!<br>
<br>
In [5]: x3d.x3d.IndexedTriangleSet<br>
Out[5]: x3d.x3d.IndexedTriangleSet</span><o:p></o:p></p>
<p>I think all that's missing is the following line in the __init__.py<o:p></o:p></p>
<p><span style="font-family:"Courier New"">from x3d import *</span><o:p></o:p></p>
<p>which will import everything that's defined in x3d.py into the __init__.py namespace and than the user an get it from "import x3d" which gives you the names defined in x3d/__init__.py<o:p></o:p></p>
<p class="MsoNormal">- Python usually makes heavy use of duck-typing (you can use any object as long as it behaves as you expect) instead of explicit "isinstance" checks. A lot of numerical computations in Python are done using the numpy (<a href="https://nam10.safelinks.protection.outlook.com/?url=https%3A%2F%2Fnumpy.org%2F&data=04%7C01%7Cbrutzman%40nps.edu%7C2c7d4294f26747a1ac8308d9ebe89cde%7C6d936231a51740ea9199f7578963378e%7C0%7C0%7C637800209456879782%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=WzfgxdbvTKLoZC5Oh87ZfjEzfjOYdFdv4nFBGyP9xFk%3D&reserved=0">https://numpy.org</a>)
 library, which implements array-based math and is optimized in C. Numpy has datatypes that are essentially similar to Python int but fail an isinstance check, and I can pass those in some, but not all places in x3d.py. Here is an example that fails:
<o:p></o:p></p>
<pre> <o:p></o:p></pre>
<pre><span class="ansi-green-fg">~/mambaforge/envs/kitchensink/lib/python3.10/site-packages/x3d/x3d.py</span> in <span class="ansi-cyan-fg">__init__</span><span class="ansi-blue-fg">(self, ccw, colorPerVertex, index, normalPerVertex, solid, color, coord, fogCoord, normal, texCoord, attrib, DEF, USE, IS, metadata, class_, id_, style_)</span><o:p></o:p></pre>
<pre><span class="ansi-green-intense-fg">  48191</span>         self<span class="ansi-blue-fg">.</span>ccw <span class="ansi-blue-fg">=</span> ccw<o:p></o:p></pre>
<pre><span class="ansi-green-intense-fg">  48192</span>         self<span class="ansi-blue-fg">.</span>colorPerVertex <span class="ansi-blue-fg">=</span> colorPerVertex<o:p></o:p></pre>
<pre><span class="ansi-green-fg">> 48193</span><span class="ansi-red-fg">         </span>self<span class="ansi-blue-fg">.</span>index <span class="ansi-blue-fg">=</span> index<o:p></o:p></pre>
<pre><span class="ansi-green-intense-fg">  48194</span>         self<span class="ansi-blue-fg">.</span>normalPerVertex <span class="ansi-blue-fg">=</span> normalPerVertex<o:p></o:p></pre>
<pre><span class="ansi-green-intense-fg">  48195</span>         self<span class="ansi-blue-fg">.</span>solid <span class="ansi-blue-fg">=</span> solid<o:p></o:p></pre>
<pre> <o:p></o:p></pre>
<pre><span class="ansi-green-fg">~/mambaforge/envs/kitchensink/lib/python3.10/site-packages/x3d/x3d.py</span> in <span class="ansi-cyan-fg">index</span><span class="ansi-blue-fg">(self, index)</span><o:p></o:p></pre>
<pre><span class="ansi-green-intense-fg">  48230</span>         <span class="ansi-green-fg">if</span>  index <span class="ansi-green-fg">is</span> <span class="ansi-green-fg">None</span><span class="ansi-blue-fg">:</span><o:p></o:p></pre>
<pre><span class="ansi-green-intense-fg">  48231</span>             index <span class="ansi-blue-fg">=</span> MFInt32<span class="ansi-blue-fg">.</span>DEFAULT_VALUE<span class="ansi-blue-fg">()</span><o:p></o:p></pre>
<pre><span class="ansi-green-fg">> 48232</span><span class="ansi-red-fg">         </span>assertValidMFInt32<span class="ansi-blue-fg">(</span>index<span class="ansi-blue-fg">)</span><o:p></o:p></pre>
<pre><span class="ansi-green-intense-fg">  48233</span>         assertNonNegative<span class="ansi-blue-fg">('index',</span> index<span class="ansi-blue-fg">)</span><o:p></o:p></pre>
<pre><span class="ansi-green-intense-fg">  48234</span>         self<span class="ansi-blue-fg">.</span>__index <span class="ansi-blue-fg">=</span> index<o:p></o:p></pre>
<pre> <o:p></o:p></pre>
<pre><span class="ansi-green-fg">~/mambaforge/envs/kitchensink/lib/python3.10/site-packages/x3d/x3d.py</span> in <span class="ansi-cyan-fg">assertValidMFInt32</span><span class="ansi-blue-fg">(value)</span><o:p></o:p></pre>
<pre><span class="ansi-green-intense-fg">   2622</span>         <span class="ansi-green-fg">if</span> <span class="ansi-green-fg">not</span> isinstance<span class="ansi-blue-fg">(</span>each<span class="ansi-blue-fg">,</span> int<span class="ansi-blue-fg">):</span><o:p></o:p></pre>
<pre><span class="ansi-green-intense-fg">   2623</span>             <span class="ansi-red-fg"># print(flush=True)</span><o:p></o:p></pre>
<pre><span class="ansi-green-fg">-> 2624</span><span class="ansi-red-fg">             </span><span class="ansi-green-fg">raise</span> X3DTypeError<span class="ansi-blue-fg">('MFInt32 list has contained value='</span> <span class="ansi-blue-fg">+</span> str<span class="ansi-blue-fg">(</span>each<span class="ansi-blue-fg">)</span> <span class="ansi-blue-fg">+</span> <span class="ansi-blue-fg">' with type='</span> <span class="ansi-blue-fg">+</span> str<span class="ansi-blue-fg">(</span>type<span class="ansi-blue-fg">(</span>each<span class="ansi-blue-fg">))</span> <span class="ansi-blue-fg">+</span> <span class="ansi-blue-fg">' which is not a valid int')</span><o:p></o:p></pre>
<pre><span class="ansi-green-intense-fg">   2625</span>     <span class="ansi-green-fg">if</span> <span class="ansi-green-fg">not</span> isValidMFInt32<span class="ansi-blue-fg">(</span>value<span class="ansi-blue-fg">):</span><o:p></o:p></pre>
<pre><span class="ansi-green-intense-fg">   2626</span>         <span class="ansi-red-fg"># print(flush=True)</span><o:p></o:p></pre>
<pre> <o:p></o:p></pre>
<pre><span class="ansi-red-fg">X3DTypeError</span>: MFInt32 list has contained value=1 with type=<class 'numpy.int64'> which is not a valid int<o:p></o:p></pre>
<pre> <o:p></o:p></pre>
<pre> <o:p></o:p></pre>
<pre>There is an easy workaround:<o:p></o:p></pre>
<pre> <o:p></o:p></pre>
<pre>x3d.IndexedTriangleSet(index = [int(x) for x in myindex]<o:p></o:p></pre>
<pre> <o:p></o:p></pre>
<pre>but it would be nice if IndexedTriangleSet accepted my numbers directly. <o:p></o:p></pre>
<pre>There are several ways of doing that, but the easiest is probably to change line 2622 to:<o:p></o:p></pre>
<pre> <o:p></o:p></pre>
<pre>if not int(x) == x: <o:p></o:p></pre>
<pre> <o:p></o:p></pre>
<p>That will work for any object that can be converted to an int, including numpy, python decimal, fraction, ..<o:p></o:p></p>
<p>- Numpy: One might consider taking numpy arrays directly, i.e. instead of <o:p>
</o:p></p>
<p>x3d.Coordinate(point=[(x1, y1, z1), (x2, y2, y3), ...])<o:p></o:p></p>
<p>one could do <o:p></o:p></p>
<p>x3d.Coordinate(point=arr)<o:p></o:p></p>
<p>where arr is a (3, n) numpy array. Now, if done naively that would require numpy as a dependency to x3d.py and it's probably good to avoid that. However, there are ways to accept numpy arrays without requiring numpy. That's a little more involved, but can
 be done (for example using decorators or a separate module (x3d.numpy_interface) or separate package (x3d-numpy)). Not sure if it's worth the effort at this point - that depends on what your future plans for this package are and how fast this is developing.<o:p></o:p></p>
<p>- Changelog. From the pypi entry and the docs on <a href="https://www.web3d.org/x3d/stylesheets/python/python.html">
https://www.web3d.org/x3d/stylesheets/python/python.html</a> it was not quite clear to me how stable the package is or where I would see changes listed, for example, if you do the change that I suggested above (accepting index values as tuples instead of a
 flat list) that would break the interface. Would you do that? Where would I find a list of changes from one version to another?<o:p></o:p></p>
<p>- Jupyter notebook: The Jupyter notebook seems like an ideal tool for work with X3D in Python, since it is rendered on the web and can display any web output. Here is a simple addition of a `_repr_html_`method to the Scene class in the x3d.py that will render
 any valid scene with no additional effort to the screen. Sure, the header is a little simplistic, but it's just a quick way to look at what your are specifying. Since I did not want to edit x3d.py itself, I simply made a new class that inherits from the x3d.Scene,
 but it would obviously be even easier if this was part of x3d itself. See <a href="https://nam10.safelinks.protection.outlook.com/?url=http%3A%2F%2Fnbviewer.org%2Fgithub%2Fhamogu%2Fx3d-experiements%2Fblob%2Fmain%2FScence_for_notebook.ipynb&data=04%7C01%7Cbrutzman%40nps.edu%7C2c7d4294f26747a1ac8308d9ebe89cde%7C6d936231a51740ea9199f7578963378e%7C0%7C0%7C637800209456879782%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=hbOIRtm2y3e67fscFuslz8j8keaEeEZz34%2BNVhYcC2U%3D&reserved=0">
http://nbviewer.org/github/hamogu/x3d-experiements/blob/main/Scence_for_notebook.ipynb</a> for an example and note how the X3D output at the bottom is not just a screenshot, but a live output that your can zoom and rotate with your mouse, even though the notebook
 is not running live, but instead you just see the rendered output of what I run some time in the past on my laptop. (I admit that this is a naive implementation and it might be useful to add a few <meta> or <WorldInfo> nodes. Also, maybe Scene is not the best
 node, or not the only node, where to define this functionality, but it seems to work well.)<o:p></o:p></p>
<div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:blue">class</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">
</span><span style="font-size:9.0pt;font-family:"Courier New";color:#267F99">Scene</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">(</span><span style="font-size:9.0pt;font-family:"Courier New";color:#267F99">x3d</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">.</span><span style="font-size:9.0pt;font-family:"Courier New";color:#267F99">Scene</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">):<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:black">   
</span><span style="font-size:9.0pt;font-family:"Courier New";color:#001080">js_source</span><span style="font-size:9.0pt;font-family:"Courier New";color:black"> =
</span><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">'https://www.x3dom.org/download/x3dom.js'</span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:black">   
</span><span style="font-size:9.0pt;font-family:"Courier New";color:#001080">css_source</span><span style="font-size:9.0pt;font-family:"Courier New";color:black"> =
</span><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">'https://www.x3dom.org/download/x3dom.css'</span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:black">   
</span><span style="font-size:9.0pt;font-family:"Courier New";color:#001080">dimension_px</span><span style="font-size:9.0pt;font-family:"Courier New";color:black"> = (</span><span style="font-size:9.0pt;font-family:"Courier New";color:#098658">600</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">,
</span><span style="font-size:9.0pt;font-family:"Courier New";color:#098658">400</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">)<o:p></o:p></span></p>
</div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p> </o:p></span></p>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:black">   
</span><span style="font-size:9.0pt;font-family:"Courier New";color:blue">def</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">
</span><span style="font-size:9.0pt;font-family:"Courier New";color:#795E26">_repr_html_</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">(</span><span style="font-size:9.0pt;font-family:"Courier New";color:#001080">self</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">):<o:p></o:p></span></p>
</div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p> </o:p></span></p>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:black">       
</span><span style="font-size:9.0pt;font-family:"Courier New";color:#AF00DB">return</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">(</span><span style="font-size:9.0pt;font-family:"Courier New";color:blue">f</span><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">"""</span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515"><html></span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">  <head></span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
</span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">     <script type='text/javascript' src='</span><span style="font-size:9.0pt;font-family:"Courier New";color:blue">{</span><span style="font-size:9.0pt;font-family:"Courier New";color:#001080">self</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">.</span><span style="font-size:9.0pt;font-family:"Courier New";color:#001080">js_source</span><span style="font-size:9.0pt;font-family:"Courier New";color:blue">}</span><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">'>
 </script> </span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">     <link rel='stylesheet' type='text/css' href='</span><span style="font-size:9.0pt;font-family:"Courier New";color:blue">{</span><span style="font-size:9.0pt;font-family:"Courier New";color:#001080">self</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">.</span><span style="font-size:9.0pt;font-family:"Courier New";color:#001080">css_source</span><span style="font-size:9.0pt;font-family:"Courier New";color:blue">}</span><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">'></link>
</span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">  </head></span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">  <body></span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">    <x3d width='</span><span style="font-size:9.0pt;font-family:"Courier New";color:blue">{</span><span style="font-size:9.0pt;font-family:"Courier New";color:#001080">self</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">.</span><span style="font-size:9.0pt;font-family:"Courier New";color:#001080">dimension_px</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">[</span><span style="font-size:9.0pt;font-family:"Courier New";color:#098658">0</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">]</span><span style="font-size:9.0pt;font-family:"Courier New";color:blue">}</span><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">px'
 height='</span><span style="font-size:9.0pt;font-family:"Courier New";color:blue">{</span><span style="font-size:9.0pt;font-family:"Courier New";color:#001080">self</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">.</span><span style="font-size:9.0pt;font-family:"Courier New";color:#001080">dimension_px</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">[</span><span style="font-size:9.0pt;font-family:"Courier New";color:#098658">1</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">]</span><span style="font-size:9.0pt;font-family:"Courier New";color:blue">}</span><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">px'>
</span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">      </span><span style="font-size:9.0pt;font-family:"Courier New";color:blue">{</span><span style="font-size:9.0pt;font-family:"Courier New";color:#001080">self</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">.XML()</span><span style="font-size:9.0pt;font-family:"Courier New";color:blue">}</span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">    </x3d></span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">  </body></span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515"></html></span><span style="font-size:9.0pt;font-family:"Courier New";color:black"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="line-height:13.5pt;background:white"><span style="font-size:9.0pt;font-family:"Courier New";color:#A31515">"""</span><span style="font-size:9.0pt;font-family:"Courier New";color:black">)<o:p></o:p></span></p>
</div>
</div>
<p><o:p> </o:p></p>
<p>Please let me know if there is anything I can do to help with this awesome package, that really makes generating X3D from Python so much simpler already.<o:p></o:p></p>
<p>Yours,<o:p></o:p></p>
<p class="MsoNormal">Moritz <o:p></o:p></p>
<pre>-- <o:p></o:p></pre>
<pre>Hans Moritz Günther<o:p></o:p></pre>
<pre>Massachusetts Institute of Technology<o:p></o:p></pre>
<pre>Kavli Institute for Astrophysics and Space Research<o:p></o:p></pre>
<pre>77 Massachusetts Avenue<o:p></o:p></pre>
<pre>NE83-569<o:p></o:p></pre>
<pre>Cambridge, MA 02139<o:p></o:p></pre>
<pre><a href="mailto:hgunther@mit.edu">hgunther@mit.edu</a><o:p></o:p></pre>
<pre><a href="https://nam10.safelinks.protection.outlook.com/?url=https%3A%2F%2Fspace.mit.edu%2Fhome%2Fguenther%2F&data=04%7C01%7Cbrutzman%40nps.edu%7C2c7d4294f26747a1ac8308d9ebe89cde%7C6d936231a51740ea9199f7578963378e%7C0%7C0%7C637800209456879782%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=HqU3N0HBlXFbNy9gvv%2BOKKLoEq2njwGf%2BVxTLSa0gSw%3D&reserved=0">https://space.mit.edu/home/guenther/</a><o:p></o:p></pre>
</div>
</body>
</html>