fusion-energy / cad_to_dagmc Goto Github PK
View Code? Open in Web Editor NEWConvert CAD geometry (STP files) or Cadquery assemblies to DAGMC h5m files
License: MIT License
Convert CAD geometry (STP files) or Cadquery assemblies to DAGMC h5m files
License: MIT License
CI currently uses conda but we could make one with pip and cmake
here is a start
# This CI will launch a Docker image that contains all the dependencies required
# within that image the pytest test suite is run
# container:
# image: continuumio/miniconda3:23.3.1-0
name: CI with install
on:
pull_request:
branches:
- main
paths-ignore:
- 'docs/**'
- '.gitignore'
- '*.md'
- 'CITATION.cff'
- 'LICENSE.txt'
- 'readthedocs.yml'
push:
branches:
- main
jobs:
testing:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: install non pypi dependencies
shell: bash
run: |
sudo apt-get --allow-releaseinfo-change update
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y libgl1-mesa-glx libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev libosmesa6 libosmesa6-dev libgles2-mesa-dev libarchive-dev libpangocairo-1.0-0
sudo apt install python3
sudo apt install python3-pip
pip install cadquery
pip install gmsh
pip install pymoab
'https://bitbucket.org/fathomteam/moab/'
https://github.com/openmc-dev/openmc/blob/develop/Dockerfile
python -m pip install .
python -c "import cad_to_dagmc"
# install openmc with dagmc and
python -m pip install .[tests]
pytest tests -v
cd examples
python create_stp_files_for_examples.py
python cadquery_assembly.py
python cadquery_compound.py
python cadquery_object_and_stp_file.py
python cadquery_text.py
python curved_cadquery_object_to_dagmc_surface_mesh.py
python curved_cadquery_object_to_dagmc_volume_mesh.py
python multiple_cadquery_objects.py
python multiple_stp_files.py
python single_stp_file_multiple_volumes.py
python single_cadquery_object.py
python single_stp_file.py
``
We should make use of the latest cadquery innovations such as imprinting which is proposed on this PR CadQuery/cadquery#1353
To test this we need ocp version 7.7.1 which is on the dev label for the cadquery channel and can be installed like this
conda install -c "cadquery/label/dev" ocp
from cadquery import importers
from OCP.GCPnts import GCPnts_QuasiUniformDeflection
import OCP
import cadquery as cq
from vertices_to_h5m import vertices_to_h5m
from OCP.TopLoc import TopLoc_Location
from OCP.BRep import BRep_Tool
from OCP.TopAbs import TopAbs_Orientation
def load_stp_file(filename: str, scale_factor: float = 1.0):
"""Loads a stp file and makes the 3D solid and wires available for use.
Args:
filename: the filename used to save the html graph.
scale_factor: a scaling factor to apply to the geometry that can be
used to increase the size or decrease the size of the geometry.
Useful when converting the geometry to cm for use in neutronics
simulations.
Returns:
CadQuery.solid, CadQuery.Wires: solid and wires belonging to the object
"""
part = importers.importStep(str(filename)).val()
if scale_factor == 1:
scaled_part = part
else:
scaled_part = part.scale(scale_factor)
solid = scaled_part
return solid
def merge_surfaces(geometry):
solids = geometry.Solids()
bldr = OCP.BOPAlgo.BOPAlgo_Splitter()
if len(solids) == 1:
solids[0].val().exportBrep(str(path_filename))
return str(path_filename)
for solid in solids:
print(type(solid))
# checks if solid is a compound as .val() is not needed for compounds
if isinstance(solid, (cq.occ_impl.shapes.Compound, cq.occ_impl.shapes.Solid)):
bldr.AddArgument(solid.wrapped)
else:
bldr.AddArgument(solid.val().wrapped)
bldr.SetNonDestructive(True)
bldr.Perform()
bldr.Images()
merged_solid = cq.Compound(bldr.Shape())
return merged_solid
def tessellate(
merged_solid, tolerance: float, angularTolerance: float = 0.1
):
merged_solid.mesh(tolerance, angularTolerance)
vertices: List[Vector] = []
triangles: List[Tuple[int, int, int]] = []
offset = 0
for s in merged_solid.Solids():
for f in s.Faces():
# todo use hashCode() to remove duplicate vertices
loc = TopLoc_Location()
poly = BRep_Tool.Triangulation_s(f.wrapped, loc)
Trsf = loc.Transformation()
reverse = (
True
if f.wrapped.Orientation() == TopAbs_Orientation.TopAbs_REVERSED
else False
)
# add vertices
vertices += [
(v.X(), v.Y(), v.Z())
for v in (v.Transformed(Trsf) for v in poly.Nodes())
]
# add triangles
triangles += [
(
t.Value(1) + offset - 1,
t.Value(3) + offset - 1,
t.Value(2) + offset - 1,
)
if reverse
else (
t.Value(1) + offset - 1,
t.Value(2) + offset - 1,
t.Value(3) + offset - 1,
)
for t in poly.Triangles()
]
offset += poly.NbNodes()
return vertices, triangles
def tessellate_parts(merged_solid, tolerance=1):
vert_tri_dict = {}
for solid in merged_solid.Solids():
for face in solid.Faces():
print(' ',face.hashCode())
stp_file = load_stp_file('example_geometry.stp')
merged_stp_file = merge_surfaces(stp_file)
vertices,triangles =tessellate(merged_stp_file, tolerance=2)
vertices_to_h5m(
vertices=vertices,
triangles=[triangles],
material_tags=["mat1"],
h5m_filename="one.h5m",
)
Looks like we can reduce the mesh element count by setting mesh.MeshSizeFactor to a large number.
OneDrive_1_16-07-2024.zip](https://github.com/user-attachments/files/16256217/OneDrive_1_16-07-2024.zip)`
Hello,
I wanted to perform a DAGMC simulation of a geometry as follows:
It is a very simple geometry with two wall thicknesses and a floor, all made of concrete.
Here is how I proceed to convert and simulate the geometry (.step file) created in a CAD software:
First, I use GMSH to create the mesh, and then I use Python:
First function:
convert_file.py
`# Libraries
from cad_to_dagmc import MeshToDagmc
import cadquery as cq
import os
from cad_to_dagmc import CadToDagmc
import time
def output_path(output_dir, output_file_name):
"""
Useful for having the output_path of the h5m file in the other functions.
Args:
output_dir (str): The directory where the output h5m file will be saved.
output_file_name (str): The name of h5m output file.
Returns:
output_path (str): The path of the h5m file
"""
return os.path.join(output_dir, output_file_name)
def mesh_geometry_to_h5m(material_tags_list, input_file_path, output_dir, output_file_name):
"""
Converts a MESH file to a DAGMC h5m file usable for simulations on OpenMC.
Args:
material_tags_list (list): The materials tags that will be applied to the volumes.
input_file_path (str): The path of the mesh file to convert
output_dir (str): The directory where the output h5m file will be saved.
output_file_name (str): The name of h5m output file.
Returns:
None
"""
# Initialize MeshToDagmc object
mesh_converter = MeshToDagmc(filename=input_file_path)
file_path = output_path(output_dir, output_file_name)
# Export DAGMC h5m file
mesh_converter.export_dagmc_h5m_file(material_tags=material_tags_list,
filename=file_path)
material_tags_list = ['mat_fw', 'mat_sw', 'mat_ceiling']
input_file_path = 'path/to/parametric_model.msh'
output_dir = 'dir'
output_file_name = 'parametric_gmsh.h5m'
start_time = time.time()
mesh_geometry_to_h5m(material_tags_list, input_file_path, output_dir, output_file_name)
end_time = time.time()
simulation_time = end_time - start_time
print(f'Meshing by gmsh took {simulation_time:.2f} `seconds')`
Conversion from .msh to .h5m, applying the different materials to the 3 volumes (WALL1, WALL2, floor).
Second function:
gmsh_sim.py
from cad_to_dagmc import CadToDagmc
import openmc
import os
import random
import time
def simulation_cad_geometry(material_tags_list, output_xml_path, input_dir, input_file_name):
"""
Run an OpenMC simulation.
Args:
material_tags_list (list): The materials tags that will be applied to the volumes.
output_xml_path (str): The path of the XML result file.
input_dir (str): The directory where the output h5m file is located.
input_file_name (str): The name of the input (.h5m) file.
Returns:
tuple: A tuple containing the result file and mesh object.
result_file (str): The path to the file containing the results.
mesh (openmc.RegularMesh): The mesh object used in the simulation.
"""
try:
# Define materials based on tags
materials = openmc.Materials()
for tag in material_tags_list:
material = openmc.Material(name=tag)
if tag == 'mat_fw':
material.add_nuclide('H1', 0.010, percent_type='wo')
material.add_nuclide('C0', 0.001416, percent_type='wo')
material.add_nuclide('O16', 0.5267, percent_type='wo')
material.add_nuclide('Na23', 0.016, percent_type='wo')
material.add_nuclide('Mg24', 0.002, percent_type='wo')
material.add_nuclide('Al27', 0.034, percent_type='wo')
material.add_element('Si', 0.337, percent_type='wo')
material.add_nuclide('B10', 0.00033, percent_type='wo')
material.add_nuclide('K39', 0.013, percent_type='wo')
material.add_nuclide('Ca40', 0.044, percent_type='wo')
material.add_nuclide('Fe56', 0.014, percent_type='wo')
material.set_density('g/cm3', 2.3)
elif tag == 'mat_sw':
material.add_nuclide('H1', 0.006, percent_type='wo')
material.add_nuclide('C0', 0.0024, percent_type='wo')
material.add_nuclide('O16', 0.5973, percent_type='wo')
material.add_nuclide('Na23', 0.016, percent_type='wo')
material.add_nuclide('Mg24', 0.002, percent_type='wo')
material.add_nuclide('Al27', 0.038, percent_type='wo')
material.add_element('Si', 0.337, percent_type='wo')
material.add_nuclide('K39', 0.013, percent_type='wo')
material.add_nuclide('Ca40', 0.044, percent_type='wo')
material.add_nuclide('Fe56', 0.014, percent_type='wo')
material.set_density('g/cm3', 2.3)
elif tag == 'mat_ceiling':
material.add_nuclide('H1', 0.010, percent_type='wo')
material.add_nuclide('C0', 0.001416, percent_type='wo')
material.add_nuclide('O16', 0.5267, percent_type='wo')
material.add_nuclide('Na23', 0.016, percent_type='wo')
material.add_nuclide('Mg24', 0.002, percent_type='wo')
material.add_nuclide('Al27', 0.034, percent_type='wo')
material.add_element('Si', 0.337, percent_type='wo')
material.add_nuclide('B10', 0.00033, percent_type='wo')
material.add_nuclide('K39', 0.013, percent_type='wo')
material.add_nuclide('Ca40', 0.044, percent_type='wo')
material.add_nuclide('Fe56', 0.014, percent_type='wo')
material.set_density('g/cm3', 2.3)
materials.append(material)
air = openmc.Material(5, "air")
air.add_nuclide('N14', 0.79)
air.add_nuclide('O16', 0.21)
air.set_density('g/cm3', 0.0012)
materials.append(air)
materials.export_to_xml()
materials.cross_sections = 'path/to/crosssections'
h5mfile_path = os.path.join(input_dir, input_file_name)
dag_univ = openmc.DAGMCUniverse(h5mfile_path)
L_square_sw = 1400
height_root = 100
height_ground = 100
height_walls = 100
height_ceiling = 100
dag_univ = openmc.DAGMCUniverse(h5mfile_path, auto_geom_ids=True)
bounding_region = dag_univ.bounding_region(bounded_type='box', boundary_type='vacuum', starting_id=10000, padding_distance=0.0)
containing_cell = openmc.Cell(region=bounding_region, fill=dag_univ)
air_cell = openmc.Cell(fill=air)
air_universe = openmc.Universe(cells=[air_cell])
containing_cell.fill = air_universe
root_universe = openmc.Universe(cells=[containing_cell])
geometry = openmc.Geometry(root_universe)
geometry.export_to_xml()
btch = 10
part = 1 * 10**6
inbatch = 0
my_settings = openmc.Settings()
my_settings.batches = btch
my_settings.inactive = inbatch
my_settings.particles = part
my_settings.seed = int(random.random() * 100) + 1
my_settings.particle = "neutron"
my_settings.run_mode = 'fixed source'
my_source = openmc.Source()
my_source.space = openmc.stats.Box((-25, -10, -10), (25, 10, 10), only_fissionable=False)
my_source.angle = openmc.stats.Isotropic()
my_source.energy = openmc.stats.Discrete([2.5e6], [1])
my_settings.source = my_source
my_settings.survival_biasing = True
my_settings.photon_transport = True
my_settings.export_to_xml()
mesh = openmc.RegularMesh()
num_divisions_x_y = int(L_square_sw / 10)
num_divisions_z = int((height_ground + height_ceiling + height_walls) / 10)
mesh.dimension = [num_divisions_x_y, num_divisions_x_y, num_divisions_z]
mesh.lower_left = [-L_square_sw / 2, -L_square_sw / 2, -height_ground]
mesh.upper_right = [+L_square_sw / 2, +L_square_sw / 2, height_walls]
mesh_filter = openmc.MeshFilter(mesh)
mesh_tally = openmc.Tally(name='tallies_on_mesh')
mesh_tally.filters = [mesh_filter]
mesh_tally.scores = ['flux']
my_tallies = openmc.Tallies([mesh_tally])
my_model = openmc.Model(materials=materials, geometry=geometry, settings=my_settings, tallies=my_tallies)
start_time = time.time()
output_filename = my_model.run()
end_time = time.time()
simulation_time = end_time - start_time
print(f'Simulation time is {simulation_time:.2f} seconds')
return 1
except Exception as e:
print(f"An error occurred: {e}")
output_xml_path = 'building_model_gmsh.xml'
material_tags_list = ['mat_fw', 'mat_sw', 'mat_ceiling']
input_dir = ''
input_file_name = 'parametric_python.h5m'
simulation_cad_geometry(material_tags_list, output_xml_path, input_dir, input_file_name)
The goal of my import is to have a box surrounding my CAD geometry by about 1 meter on all sides. I also want to fill the box with air, knowing that the concrete materials have already been assigned to the volumes.
I perform my simulation and I do not get anything that resembles what might be expected. There is no attenuation in the flux at the walls.
In my opinion, the function that collects data from the output file tallies.out is correct as I have used it in other simulations and it displayed expected results. I think that the way I coded the geometry import in gmsh_sim.py and the setup of the cells and universes might be incorrect, and this could be the source of the wrong results . Finally , to compare , I added a plot of openmc simulation with an openmc-made geometry wich is similar to the cad model so you can see what I would want to except orignally from the malfunctionnin simulation
Could you please help me?
Have a good day.
Best regards.
Hello,
I am running neutronics simulations on a tokamak center column shield with some arbitrary, circular, cooling pipes in them using cad_to_dagmc to convert my step-file. The CAD looks like below:
When I plot the geometry using openmc, however, the cooling pipes are suddenly very square. Is this simply a plotting issue or do you think the geometry as a whole is wrong for the actual neutronics simulations as well?
Hi ,
I'm trying to use cad_to_dagmc for step files from CATIA in order to being able to undergo simulations on it.
Here is my code I want to use :
def step_to_openmc_h5m(input_step_file_path: str, output_file_name: str, output_dir: str) -> str:
"""Converts a STEP file to a DAGMC h5m file usable for simulations on OpenMC.
Args:
input_step_file_path (str): The path to the input STEP file.
output_file_name (str): The desired name of the output h5m file.
output_dir (str): The directory where the output h5m file will be saved.
Returns:
str: The path to the generated h5m file.
"""
try:
# Initialize CadToDagmc instance
converter = CadToDagmc()
# Add the STEP file to the converter
converter.add_stp_file(input_step_file_path)
# Generate the output h5m file path
output_h5m_file_path = os.path.join(output_dir, output_file_name)
# Export the DAGMC h5m file
converter.export_dagmc_h5m_file(filename=output_h5m_file_path)
return output_h5m_file_path
except Exception as e:
print(f"Error occurred while converting the STEP file: {e}")
return ""
, I am using a step file from your geddit page : extrude_rectangle.step , for a basic test , but it does not work and I have the Error that is displayed.
I would like to know what I did wrong in my code.
Sorry in advance if this page is not intended to do code corrections , I'm not familiar with geddit.
openmc execuatable can be checked with
openmc.lib._dagmc_enabled():
perhaps we should add this check and warn the user
gmsh allows for certain algorithms to parallelize the meshing operation, e.g. of possible implementation
gmsh.option.setNumber("Mesh.MaxNumThreads1D", number_of_threads)
gmsh.option.setNumber("Mesh.MaxNumThreads2D", number_of_threads)
gmsh.option.setNumber("Mesh.MaxNumThreads3D", number_of_threads)
Recently cadquery master was updated to ocp 7.7.2
no openmc 0.13.3 with dagmc no longer installs via conda
so we can
for now I'm removing this line from the install script in ci
mamba install -y -c conda-forge "openmc=0.13.3=dagmc*nompi*"
and putting in the build from source option
Hi All,
I have created a h5m model using the cad_to_dagmc conversion. It uses the DEMO model found in paramak. The layers of the blanket have been sliced into thin segments for better resolution of the neutronics in OpenMC. I have found a change in volume of the layers before and after the mesh that is up to 20% difference in some of the layers. I used CAD to give me the volumes of the objects before hand. I then converted the files to h5m and used OpenMC's stochastic volumes finder and found large differences between the two. There seems to be some issue when creating the mesh of the object. Any help or work around would be helpful. Below is the difference between the two measurements for each layer
OpenMC | FreeCAD | Percentage Diff
8832000 | 7985387 | 90.4142549818841
18238000 | 18305705 | 100.37123039807
20200000 | 18745010 | 92.7970792079208
19248000 | 19182706 | 99.6607751454697
21572000 | 19619631 | 90.9495225292045
24232000 | 20056649 | 82.7692679102014
24184000 | 20494116 | 84.7424578233543
23466000 | 20931891 | 89.2009332651496
23490000 | 21370217 | 90.9758067262665
25524000 | 21809467 | 85.446900955963
24600000 | 22249448 | 90.4449105691057
25080000 | 22690541 | 90.4726515151515
24934000 | 23133006 | 92.7769551616267
22920000 | 23577108 | 102.866963350785
22330000 | 24023068 | 107.582033139275
22372000 | 24470972 | 109.38213838727
22996000 | 24921086 | 108.371395025222
Hello,
Thank you for creating this library!
I have been trying to use it to convert a .stp file to .h5m as described in the examples ( surface_mesh / single_stp_file.py). However it seems the process fails for me because original_ids
and scrambled_ids
(line 565-566 of core.py) end up having a different size and the comments in the code tell me that this should not be the case.
Unfortunately I cannot share the .stp file I am using, however if there are some things I can try to investigate this issue, please let me know.
Hi Jon,
I tried installing cad-to-dagmc but can't run anything.
Here's my Dockerfile
FROM continuumio/miniconda3
RUN conda config --add channels conda-forge
RUN conda install mamba && \
mamba install -c conda-forge openmc && \
mamba install -c fusion-energy -c cadquery -c conda-forge cad_to_dagmc
When running from cad_to_dagmc import CadToDagmc
, I have the following error:
File "/home/convert_cad.py", line 5, in <module>
from cad_to_dagmc import CadToDagmc
File "/opt/conda/lib/python3.9/site-packages/cad_to_dagmc/__init__.py", line 1, in <module>
from .core import CadToDagmc
File "/opt/conda/lib/python3.9/site-packages/cad_to_dagmc/core.py", line 4, in <module>
from cadquery import importers
File "/opt/conda/lib/python3.9/site-packages/cadquery/__init__.py", line 10, in <module>
from .occ_impl.geom import Plane, BoundBox, Vector, Matrix, Location
File "/opt/conda/lib/python3.9/site-packages/cadquery/occ_impl/geom.py", line 5, in <module>
from OCP.gp import (
ImportError: libGL.so.1: cannot open shared object file: No such file or directory
Maybe the installation instructions should be extended to include libGL?
cad-to-dagmc can currently read in stp files and in memory cadquery objects.
Adding the ability to read in .msh mesh files would be really handy. Not just as it is super input format to support but also this would allow user to refine the msh
First people could export the msh, refine it the msh and then import it again
Refining can be done with tools like mmg or pymmg by the user
this would be more flexible then handling the refining internally as other packages for refining might be desired, or the user might want to manually remesh.
To keep the CI concise we can make use of the openmc docker image that includes dagmc.
The trouble is that this docker image currently uses an older version of python and we need minimum python 3.10
If this PR gets merged in then we get python 3.10 in the docker image ๐ and I can continue on the CI that just uses pip installs (no conda)
Hi all!
I am trying to follow the installation instructions here:
https://pypi.org/project/cad-to-dagmc/
Install using Conda and pip
However, when I run a simple script
import cad_to_dagmc
I have the following error:
Traceback (most recent call last):
File "/home/marija/main.py", line 1, in
import cad_to_dagmc
File "/usr/local/bin/conda/envs/env_d/lib/python3.10/site-packages/cad_to_dagmc/init.py", line 16, in
from .core import *
File "/usr/local/bin/conda/envs/env_d/lib/python3.10/site-packages/cad_to_dagmc/core.py", line 10, in
from pymoab import core, types
ModuleNotFoundError: No module named 'pymoab'
Have anyone seen it before? Are there extra installation steps needed?
I am converting cadquery geometry to a dagmc h5m file, and I keep getting the following error:
AttributeError: 'OCP.TopoDS.TopoDS_Compound' object has no attribute '_address'
The error comes from the following lines of code in cad_to_dagmc:
gmsh, volumes = _mesh_brep(
brep_object=imprinted_assembly.wrapped._address(), # in memory address
min_mesh_size=min_mesh_size,
max_mesh_size=max_mesh_size,
mesh_algorithm=mesh_algorithm,
)
Has anyone seen this problem before?
I believe it must be to do with my environment - I am using github codespaces to run this. This is because when I run the exact same code on my local computer in an environment that I made following the same install order as the codespace it runs fine. My Dockerfile in the codespace installs the relevant packages like this:
RUN apt-get --yes install libeigen3-dev \
# sudo \
# sudo is needed during the NJOY install
git \
wget \
gfortran \
g++ \
mpich \
libmpich-dev \
libhdf5-serial-dev \
libhdf5-mpich-dev \
hdf5-tools \
imagemagick \
cmake \
# libnetcdf-dev is needed to allow NETCDF on MOAB which helps with tet meshes in OpenMC
libnetcdf-dev \
# libtbb-dev required for DAGMC
libtbb-dev \
# libglfw3-dev required for DAGMC
libglfw3-dev \
# needed for CadQuery functionality
libgl1-mesa-glx \
# needed for CadQuery functionality
libgl1-mesa-dev \
# needed for CadQuery functionality
libglu1-mesa-dev \
# needed for CadQuery functionality
freeglut3-dev \
# needed for CadQuery functionality
libosmesa6 \
# needed for CadQuery functionality
libosmesa6-dev \
# needed for CadQuery functionality
libgles2-mesa-dev \
# needed for Gmsh functionality
libxft2
# installing cadquery and jupyter
RUN conda install -c conda-forge -c python python=3.10
RUN conda install mamba
RUN mamba install -y -c conda-forge "moab>=5.3.0" gmsh python-gmsh
RUN pip install cad_to_dagmc==0.6.2
RUN mamba install -c conda-forge -y "openmc=0.14.0=dagmc*nompi*"
RUN pip install openmc_data_downloader
RUN pip install cadquery
Many thanks
instead of installing gmsh we could potential use cadquery to facet the geometry.
here is some code that doesn't quite produce watertight geometry but looks like it is close
this didn't produce non overlapping water tight parts when the geometry was in contact with other surfaces
def tessellate(parts, tolerance: float = 0.1, angularTolerance: float = 0.1):
"""Creates a mesh / faceting / tessellation of the surface"""
parts.mesh(tolerance, angularTolerance)
offset = 0
vertices: List[Vector] = []
triangles = {}
for f in parts.Faces():
loc = TopLoc_Location()
poly = BRep_Tool.Triangulation_s(f.wrapped, loc)
Trsf = loc.Transformation()
reverse = (
True
if f.wrapped.Orientation() == TopAbs_Orientation.TopAbs_REVERSED
else False
)
# add vertices
face_verticles = [
(v.X(), v.Y(), v.Z()) for v in (v.Transformed(Trsf) for v in poly.Nodes())
]
vertices += face_verticles
face_triangles = [
(
t.Value(1) + offset - 1,
t.Value(3) + offset - 1,
t.Value(2) + offset - 1,
)
if reverse
else (
t.Value(1) + offset - 1,
t.Value(2) + offset - 1,
t.Value(3) + offset - 1,
)
for t in poly.Triangles()
]
triangles[f.hashCode()] = face_triangles
offset += poly.NbNodes()
list_of_triangles_per_solid = []
for s in parts.Solids():
triangles_on_solid = []
for f in s.Faces():
triangles_on_solid += triangles[f.hashCode()]
list_of_triangles_per_solid.append(triangles_on_solid)
for vert in vertices:
for tri in list_of_triangles_per_solid:
return vertices, list_of_triangles_per_solid
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.