Languages

Previous versions

1.2
1.1

Source code for openPLM.apps.document3D.STP_converter_WebGL

##Copyright 2008-2011 Thomas Paviot (tpaviot@gmail.com)
##
##This file is part of pythonOCC.
##
##pythonOCC is free software: you can redistribute it and/or modify
##it under the terms of the GNU Lesser General Public License as published by
##the Free Software Foundation, either version 3 of the License, or
##(at your option) any later version.
##
##pythonOCC is distributed in the hope that it will be useful,
##but WITHOUT ANY WARRANTY; without even the implied warranty of
##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##GNU Lesser General Public License for more details.
##
##You should have received a copy of the GNU Lesser General Public License
##along with pythonOCC.  If not, see <http://www.gnu.org/licenses/>.



import os.path
from OCC.STEPCAFControl import STEPCAFControl_Reader
from OCC import XCAFApp, TDocStd, XCAFDoc
from OCC.TCollection import TCollection_ExtendedString, TCollection_AsciiString
from OCC.TDF import TDF_LabelSequence, TDF_Tool, TDF_Label
from OCC.Utils.Topology import Topo
from OCC.TDataStd import Handle_TDataStd_Name, TDataStd_Name_GetID
from OCC.Quantity import Quantity_Color
from OCC.Bnd import Bnd_Box
from OCC.TopLoc import TopLoc_Location
from OCC.BRepMesh import BRepMesh_Mesh
from OCC.BRepBndLib import BRepBndLib_Add
from OCC.BRep import BRep_Tool_Triangulation
from mesh import GeometryWriter, get_mesh_precision
from classes import (Link, Product, TransformationMatrix,  search_assembly,
        get_available_name)
from OCC.GarbageCollector import garbage


def new_collect_object(self, obj_deleted):
    self._kill_pointed()

garbage.collect_object=new_collect_object


[docs]class StepImporter(object): """ :param file_path: Path of the file **.stp** to analyzing :param id: For the generation of the :class:`.Product`, **id** is assigned like product.doc_id for every node of :class:`.Product`. For the generation of the files of geometry **.geo**, **id** , together with an index generated by the class, are used to identify the content of every file Generates from a path of :class:`~django.core.files.File` **.stp**: -A set of files **.geo** that represents the geometry of the different simple products that are useful to realize the visualization 3D across the web browser. -A structure of information that represents the arborescencse of the different assemblies,represented in a :class:`.Product` . (Including his spatial location and orientation and his label of reference (:class:`.OCC.TDF.TDF_Label`)) This class is invoked from three different subprocesses related to the functionality of pythonOCC(generate3D.py , generateComposition.py , generateDecomposition.py). """ def __init__(self, file_path, id=None): self.file = file_path.encode("utf-8") self.id = id self.shapes_simples = [] self.main_product=None basename = os.path.basename(self.file) self.fileName = os.path.splitext(basename)[0] self.STEPReader = STEPCAFControl_Reader() if self.STEPReader.ReadFile(self.file) != 1: raise OCCReadingStepError self.h_doc = TDocStd.Handle_TDocStd_Document() self.app = XCAFApp.GetApplication().GetObject() self.app.NewDocument(TCollection_ExtendedString("MDTV-XCAF"), self.h_doc) self.STEPReader.Transfer(self.h_doc) self.doc = self.h_doc.GetObject() self.h_shape_tool = XCAFDoc.XCAFDoc_DocumentTool_ShapeTool(self.doc.Main()) self.h_colors_tool = XCAFDoc.XCAFDoc_DocumentTool_ColorTool(self.doc.Main()) self.shape_tool = self.h_shape_tool.GetObject() self.color_tool=self.h_colors_tool.GetObject() self.shapes = TDF_LabelSequence() self.shape_tool.GetShapes(self.shapes) for i in range(self.shapes.Length()): shape = self.shapes.Value(i+1) if self.shape_tool.IsSimpleShape(shape): compShape = self.shape_tool.GetShape(shape) t = Topo(compShape) if t.number_of_vertices() > 0: label = get_label_name(shape) color = find_color(shape, self.color_tool, self.shape_tool) self.shapes_simples.append(SimpleShape(label, compShape, color)) roots = TDF_LabelSequence() self.shape_tool.GetFreeShapes(roots) self.thumbnail_valid = False if roots.Length() == 1: shape = self.shape_tool.GetShape(roots.Value(1)) t = Topo(shape) if t.number_of_vertices() > 0: bbox = Bnd_Box() gap = 0 bbox.SetGap(gap) BRepMesh_Mesh(shape, get_mesh_precision(shape, 1)) faces_iterator = Topo(shape).faces() for F in faces_iterator: face_location = TopLoc_Location() BRep_Tool_Triangulation(F, face_location) BRepBndLib_Add(shape, bbox) x_min, y_min, z_min, x_max, y_max, z_max = bbox.Get() diagonal = max(x_max - x_min, y_max - y_min, z_max - z_min) if diagonal > 0: self.scale = 200. / diagonal self.trans = ((x_max - x_min) / 2. - x_max, (y_max - y_min) / 2. - y_max, (z_max - z_min) / 2. - z_max) self.thumbnail_valid = True ws = self.STEPReader.Reader().WS().GetObject() model = ws.Model().GetObject() model.Clear()
[docs] def compute_geometries(self,root_path, pov_dir): """ :param root_path: Path where to store the files **.geo** generated When we generate a new :class:`.StepImporter` we will refill a list(**shapes_simples**) whit the :class:`.SimpleShape` contained in the file **.stp** For each :class:`.SimpleShape` in the list **shapes_simples**: We call the method :func:`.write_geometries` to generate a file **.geo** representative of its geometry,the content of the file is identified by the index+1 (>0) of the position of the :class:`.SimpleShape` in the list of **SimpleShapes** and by the attribue id of :class:`.StepImporter` Returns the list of the path of the generated **.geo** files """ files_index="" self.povs = [] for index, shape in enumerate(self.shapes_simples): name=get_available_name(root_path,self.fileName+".geo") path=os.path.join(root_path, name) identifier="_"+str(index+1)+"_"+str(self.id) writer = GeometryWriter(shape, 0.3) pov_filename = os.path.join(pov_dir, os.path.basename(path + ".inc")) writer.write_geometries(identifier, path, pov_filename) files_index+="GEO:"+name+" , "+str(index+1)+"\n" if writer.triangle_count: self.povs.append((os.path.basename(name + ".inc"), identifier)) return files_index
[docs] def generate_product_arbre(self): """ Generates a :class:`.Product` relative to the assemblies of the file **.stp**, for every node of the :class:`.Product` it includes a label (:class:`.OCC.TDF.TDF_Label`) that represents and identifies the node , openPLM can only work whit a single root **.stp** files """ roots = TDF_LabelSequence() self.shape_tool.GetFreeShapes(roots) if roots.Length() != 1: raise MultiRootError deep = 0 product_id = [1] root = roots.Value(1) name = get_label_name(root) self.main_product = Product(name, deep, root, self.id, product_id[0], self.file) product_id[0] += 1 expand_product(self.shape_tool,self.main_product, self.shapes_simples, deep+1, self.id, self.main_product, product_id, self.file) return self.main_product
[docs]class SimpleShape(): """ Class used to represent a simple shape geometry (not assembly) :model attributes: .. attribute:: name Name of geometry .. attribute:: TopoDS_Shape :class:`.OCC.TopoDS.TopoDS_Shape` that contains the geometry .. attribute:: color :class:`.OCC.Quantity.Quantity_Color` that contains information about color of geometry """ def __init__(self, name,TopoDS_Shape,color): self.name = name self.shape = TopoDS_Shape #OCC.TopoDS.TopoDS_Shape self.color = color
[docs]def expand_product(shape_tool,product,shapes_simples,deep,doc_id,product_root,product_id,file_path): """ :param shape_tool: :class:`.OCC.XCAFDoc.XCAFDoc_ShapeTool` :param product: :class:`.Product` that will be expanded :param shapes_simples: list of :class:`.SimpleShape` :param deep: Depth of the node that we explore :param doc_id: id that references a :class:`.DocumentFile` of which we are generating the :class:`.Product` :param product_root: :class:`.Product` root of the arborescense We are going to expand a :class:`.Product` (**product**) from the :class:`.OCC.TDF.TDF_Label` who identifies it (**product**.label_reference) If the **product** is an assembly: * We generate the **list** of the :class:`.OCC.TDF.TDF_Label` that define it * for each :class:`.OCC.TDF.TDF_Label` in **list**: - We generate a new :class:`.document3D.classes.Link` or if two or more :class:`.OCC.TDF.TDF_Label` of the list are partner, add an occurrence extra to the :class:`.document3D.classes.Link` that already was generated - The :class:`.document3D.classes.Link` is going to point at a new :class:`.Product` or, if the :class:`.Product` is already present in **product_root**, at the already definite product - If the :class:`.document3D.classes.Link` pointed at a new :class:`.Product` we need to expand it * The atribute **label_reference** of the new :class:`.Product` should be the :class:`.OCC.TDF.TDF_Label` * We expand the :class:`.Product` in a recursive call of method Else the **product** is a simple shape: * We look in the list of **shapes_simples** for his partner * We set the attribute **product**.geometry like the index+1 (>0) of the position of his partner in the list of **SimpleShape** """ if shape_tool.IsAssembly(product.label_reference): l_c = TDF_LabelSequence() shape_tool.GetComponents(product.label_reference,l_c) for i in range(l_c.Length()): label = l_c.Value(i+1) if shape_tool.IsReference(label): label_reference=TDF_Label() shape_tool.GetReferredShape(label, label_reference) reference_found = False matrix = TransformationMatrix(get_matrix(shape_tool.GetLocation(label).Transformation())) shape = shape_tool.GetShape(label_reference) for link in product.links: if shape_tool.GetShape(link.product.label_reference).IsPartner(shape): link.add_occurrence(get_label_name(label), matrix) reference_found = True break if not reference_found: new_product = Product(get_label_name(label_reference), deep, label_reference, doc_id, product_id[0], file_path) product_assembly = search_assembly(new_product, product_root) if product_assembly: product.links.append(Link(product_assembly)) else: product.links.append(Link(new_product)) product_id[0] += 1 expand_product(shape_tool, new_product, shapes_simples, deep+1, doc_id, product_root,product_id, file_path) product.links[-1].add_occurrence(get_label_name(label), matrix) else: compShape = shape_tool.GetShape(product.label_reference) for index in range(len(shapes_simples)): if compShape.IsPartner(shapes_simples[index].shape): product.set_geometry(index+1) #to avoid index==0
[docs]def get_matrix(location): """ Converts *location* in an array ([x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4]) == == == == == = == x1 x2 x3 x4 x = x' y1 y2 y3 y4 y = y' z1 z2 z3 z4 z = z' 0 0 0 1 1 = 1 == == == == == = == :param location: location :type location: :class:`.OCC.TopLoc.TopLoc_Location` """ m = location.VectorialPart() gp = m.Row(1) x1 = gp.X() x2 = gp.Y() x3 = gp.Z() x4 = location.Transforms()[0] gp = m.Row(2) y1 = gp.X() y2 = gp.Y() y3 = gp.Z() y4 = location.Transforms()[1] gp = m.Row(3) z1 = gp.X() z2 = gp.Y() z3 = gp.Z() z4 = location.Transforms()[2] return [x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4]
[docs]def get_label_name(lab): """ Returns the name of a :class:`.OCC.TDF.TDF_Label` (**lab**) :param lab: :class:`.OCC.TDF.TDF_Label` """ entry = TCollection_AsciiString() TDF_Tool.Entry(lab,entry) N = Handle_TDataStd_Name() lab.FindAttribute(TDataStd_Name_GetID(),N) n=N.GetObject() return unicode(n.Get().PrintToString(),errors='ignore')#.decode("latin-1")
[docs]def set_label_name(label, name): """ Sets the name of a :class:`.OCC.TDF.TDF_Label` (**label**) :param label: :class:`.OCC.TDF.TDF_Label` :param name: new name for a :class:`.OCC.TDF.TDF_Label` """ entry = TCollection_AsciiString() TDF_Tool.Entry(label, entry) N = Handle_TDataStd_Name() label.FindAttribute(TDataStd_Name_GetID(),N) n=N.GetObject() n.Set(TCollection_ExtendedString(name.encode("latin-1")))
[docs]def find_color(label, color_tool, shape_tool): """ Gets the color of a :class:`.OCC.TDF.TDF_Label` (**label**) :param label: :class:`.OCC.TDF.TDF_Label` :param shape_tool: :class:`.OCC.XCAFDoc.XCAFDoc_ShapeTool` :param color_tool: :class:`.OCC.XCAFDoc.XCAFDoc_ColorTool` """ c = Quantity_Color() if (color_tool.GetInstanceColor(shape_tool.GetShape(label), 0, c) or color_tool.GetInstanceColor(shape_tool.GetShape(label), 1, c) or color_tool.GetInstanceColor(shape_tool.GetShape(label), 2, c)): for i in (0, 1, 2): color_tool.SetInstanceColor(label, i, c) return c if (color_tool.GetColor(label, 0, c) or color_tool.GetColor(label, 1, c) or color_tool.GetColor(label, 2, c)): shape = shape_tool.GetShape(label) for i in (0, 1, 2): color_tool.SetInstanceColor(shape, i, c) return c return False
class MultiRootError(Exception): def __unicode__(self): return u"OpenPLM does not support files step with multiple roots" class OCCReadingStepError(Exception): def __unicode__(self): return u"PythonOCC could not read the file"