Changeset 1022 in main


Ignore:
Timestamp:
04/24/12 07:57:30 (7 years ago)
Author:
agalech
Message:

Documentation for Document3D

Location:
trunk/openPLM/document3D
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/openPLM/document3D/STP_converter_WebGL.py

    r1005 r1022  
    2929from classes import * 
    3030from OCC.GarbageCollector import garbage 
    31 #from openPLM.document3D.models import media3DGeometryFile 
     31 
    3232""" 
    3333l_SubShapes = TDF_LabelSequence() 
     
    4848class NEW_STEP_Import(object): 
    4949 
    50  
    51     
     50    """ 
     51    Class capable of generating from a file .step:  
     52     
     53    -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.  
     54     
     55    -A structure of information that represents the arborescencse of the different assamblajes,represented in a  :class:`.Product` . (Including his spatial location and orientation) 
     56   """ 
    5257     
    5358    def __init__(self, file_path,id=None): 
     
    6671 
    6772        if not self.STEPReader.ReadFile(self.file) == 1: 
    68             print "False" 
     73            raise OCC_ReadingStep_Error 
    6974                
    7075        self.h_doc = TDocStd.Handle_TDocStd_Document() 
    7176        self.app = XCAFApp.GetApplication().GetObject() 
    72         self.app.NewDocument(TCollection_ExtendedString("XmlXCAF"),self.h_doc) 
     77        self.app.NewDocument(TCollection_ExtendedString("MDTV-XCAF"),self.h_doc) 
    7378        """ 
    74           Formats.Append(TCollection_ExtendedString ("MDTV-XCAF"));   
     79          Formats.Append(TCollection_ExtendedString (""));   
    7580          Formats.Append(TCollection_ExtendedString ("XmlXCAF")); 
    7681          Formats.Append(TCollection_ExtendedString ("XmlOcaf")); 
     
    104109 
    105110        files_index="" 
    106  
     111         
    107112        for index, shape in enumerate(self.shapes_simples): 
    108113                name=get_available_name(location,self.fileName+".geo") 
    109114                path=os.path.join(location, name) 
    110                 mesh_shape(shape,path,"_"+str(index)+"_"+str(self.id)) 
    111                 files_index+="GEO:"+name+" , "+str(index)+"\n" 
     115                mesh_shape(shape,path,"_"+str(index+1)+"_"+str(self.id)) #index+1 
     116                files_index+="GEO:"+name+" , "+str(index+1)+"\n" #index+1 
    112117              
    113118      
     
    118123        roots = TDF_LabelSequence() 
    119124        self.shape_tool.GetFreeShapes(roots) 
    120         #prohibir step conj 2 ROOTS 
    121         deep=0 
    122         for i in range(roots.Length()): 
    123              
    124             self.product_relationship_arbre=Product(GetLabelNom(roots.Value(i+1)),deep,roots.Value(i+1),self.id,self.file)  
    125             parcour_product_relationship_arbre(roots.Value(i+1),self.shape_tool,self.product_relationship_arbre,self.shapes_simples, 
    126             (deep+1),self.id,self.product_relationship_arbre) 
     125        if not roots.Length()==1: 
     126            raise MultiRoot_Error 
     127 
     128        deep=0             
     129        self.product_relationship_arbre=Product(GetLabelNom(roots.Value(1)),deep,roots.Value(1),self.id,self.file)  
     130        parcour_product_relationship_arbre(roots.Value(1),self.shape_tool,self.product_relationship_arbre,self.shapes_simples, 
     131        (deep+1),self.id,self.product_relationship_arbre) 
    127132        
    128133        return self.product_relationship_arbre 
     
    151156     
    152157def parcour_product_relationship_arbre(label,shape_tool,product,shapes_simples,deep,doc_id,product_root): 
    153     #un parcour para ver si existen 2 nodos con el mismo nombre o algun nodo sin nombre al principio antes de empezar 
    154  
    155     #colour_chercher(label,color_tool,shape_tool) 
     158 
    156159    if shape_tool.IsAssembly(label): 
    157         # si no tiene nombre lanzar excepcion 
    158160        l_c = TDF_LabelSequence() 
    159161        shape_tool.GetComponents(label,l_c) 
     
    171173                else: 
    172174 
    173                     product_assembly=search_assembly(GetLabelNom(label_reference),label_reference,doc_id,product_root) 
     175                    product_assembly=search_assembly(GetLabelNom(label_reference),label_reference,doc_id,product_root,shape_tool.IsSimpleShape(label_reference)) 
    174176                              
    175177                    if product_assembly:   
     
    186188        compShape=shape_tool.GetShape(label) 
    187189 
    188         #nous cherchons sa correspondance dans la liste de shapes simples / si le shape n avais pas de vertices on ne trouvera aucun shape  
     190         
    189191                       
    190192        for index in range(len(shapes_simples)): 
    191193            if compShape.IsPartner(shapes_simples[index].shape): 
    192                 product.set_geometry(index) # to evade product.geometry=0 
     194                product.set_geometry(index+1) #to avoid index==0 
    193195                    
    194196 
     
    197199     
    198200 
    199          
     201def getMatrixFromLocation(Location): 
     202 
     203 
     204    m=Location.VectorialPart() 
     205    gp=m.Row(1) 
     206    x1=gp.X()            
     207    x2=gp.Y() 
     208    x3=gp.Z() 
     209    x4=Location.Transforms()[0] 
     210    gp=m.Row(2) 
     211    y1=gp.X()           
     212    y2=gp.Y() 
     213    y3=gp.Z() 
     214    y4=Location.Transforms()[1] 
     215    gp=m.Row(3) 
     216    z1=gp.X()          
     217    z2=gp.Y() 
     218    z3=gp.Z() 
     219    z4=Location.Transforms()[2]    
     220    return [x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4]           
    200221         
    201222def GetLabelNom(lab): 
     
    217238    n=N.GetObject() 
    218239    n.Set(TCollection_ExtendedString(nom.encode("latin-1"))) 
    219     return True 
     240 
    220241  
    221242   
     
    225246        color_tool.SetColor(label,c,0) 
    226247        color_tool.SetColor(label,c,1) 
    227         color_tool.SetColor(label,c,2) #para no tener problemas a la hora de componer y no perder informacion del color 
    228         #print "Color encontrado manera 1(",c.Red(),",",c.Green() ,"," ,c.Blue() ,    ") encontrado para : " , GetLabelNom(label)  
     248        color_tool.SetColor(label,c,2)  
     249 
    229250        return c 
    230251     
     
    233254        color_tool.SetInstanceColor(shape_tool.GetShape(label),1,c) 
    234255        color_tool.SetInstanceColor(shape_tool.GetShape(label),2,c) 
    235         #print "Color encontrado manera 2 (",c.Red(),",",c.Green() ,"," ,c.Blue() ,    ") encontrado para : " , GetLabelNom(label)  
     256        
    236257        return c 
    237258 
    238259    return False 
    239260 
     261  
     262    
     263class MultiRoot_Error(Exception): 
     264    def __unicode__(self): 
     265        return u"OpenPLM does not support files step with multiple roots"     
     266class OCC_ReadingStep_Error(Exception): 
     267    def __unicode__(self): 
     268        return u"PythonOCC could not read the file" 
     269 
  • trunk/openPLM/document3D/arborescense.py

    r1007 r1022  
    11import os, os.path 
    2 from openPLM.plmapp.controllers.part import PartController 
    3 from classes import * 
    4 import classes as classes  
    5 from openPLM.plmapp.models import * 
    6 from openPLM.plmapp.models import DocumentFile 
     2 
    73import django.utils.simplejson as json 
    84     
    95def generate_javascript_for_3D(product): 
    10  
     6    """ 
     7     
     8    :param product: :class:`.Product` that represents the arborescense of the :class:`.DocumentFile` that we want to show 
     9     
     10    From a :class:`.Product`  generates the code javascript necessarily to locate and to show the different geometries that compose the visualization 3D 
     11     
     12    """ 
    1113    if product: 
    1214        numeration=[0] 
     
    3941    javascript_menu[0]+="<ul>" 
    4042         
    41     if product.geometry==None: 
     43    if product.geometry==False: 
    4244        parts_generated=[] 
    4345              
     
    121123    return locate 
    122124     
    123 def read_ArbreFile(doc_file,recursif=None): 
    124  
    125     from models import  ArbreFile  
    126     try: 
    127         new_ArbreFile=ArbreFile.objects.get(stp=doc_file) 
    128     except: 
    129         return False 
    130  
    131     #product , visited =generateArbre(json.loads(new_ArbreFile.file.read())) 
    132     product =generateArbre(json.loads(new_ArbreFile.file.read())) 
    133     if recursif and product: 
    134         add_child_ArbreFile(doc_file,product,product_root=product,deep=1)         
    135              
    136     return product 
    137      
    138  
    139      
    140      
    141 def add_child_GeometryFiles(doc_file,files_to_add): 
    142 #ahora puede tener 2 veces el mismo recorrido 
    143     from models import  GeometryFile 
    144     stp_related ,list_loc=get_step_related(doc_file) 
    145     for stp in stp_related:  
    146         files_to_add+=list(GeometryFile.objects.filter(stp=stp)) 
    147         add_child_GeometryFiles(stp,files_to_add) 
    148                          
    149                              
    150                              
    151 def add_child_ArbreFile(doc_file,product,product_root,deep): 
    152  
    153     from models import  ArbreFile 
    154     stp_related,list_loc=get_step_related(doc_file) 
    155  
    156     for i,stp in enumerate(stp_related):     
    157         #try: 
    158          
    159         new_ArbreFile=ArbreFile.objects.get(stp=stp) 
    160         #new_product, visited =generateArbre(json.loads(new_ArbreFile.file.read()),product=False,product_root=product_root,deep=deep,from_child_ArbreFile=product) 
    161         new_product=generateArbre(json.loads(new_ArbreFile.file.read()),product=False,product_root=product_root,deep=deep,from_child_ArbreFile=product)                                                                                      
    162         for location in list_loc[i]: 
    163             product.links[-1].add_occurrence(location.name,location) 
    164              
    165         if new_product: 
    166             add_child_ArbreFile(stp,new_product,product_root,deep+1)                        
    167         #except: 
    168  
    169             #pass 
    170  
    171                               
    172  
    173 def get_step_related(doc_file,locations=None): 
    174     from models import Document3D ,Location_link , is_stp 
    175     stp_related=[] 
    176     list_loc=[] 
    177     Doc3D=Document3D.objects.get(id=doc_file.document.id) 
    178     part=Doc3D.PartDecompose 
    179      
    180     if part: 
    181         list_link=ParentChildLink.objects.filter(parent=part, end_time=None) 
    182         for i in range(len(list_link)): 
    183             locations=list(Location_link.objects.filter(link=list_link[i])) 
    184             if locations:  
    185                 part_child=list_link[i].child 
    186                 part_controller=PartController(part_child,None) 
    187                 list_doc=part_controller.get_attached_documents() 
    188                  
    189                 for Doc_Part_Link in list_doc: 
    190                     if Doc_Part_Link.document.type=="Document3D": 
    191                         STP_file=Doc_Part_Link.document.files.filter(is_stp) 
    192                         if STP_file.exists(): 
    193                             stp_related.append(STP_file[0]) 
    194                             list_loc.append(locations) 
    195                         else: 
    196                             pass 
    197                             #raise Document3D_link_Error 
    198                              
    199                         break 
    200  
    201     return stp_related , list_loc 
    202                              
    203                                                         
    204  
    205      
    206      
    207  
    208          
    209 def generate_ArbreFile(product,doc_file): 
    210  
    211  
    212     from models import  ArbreFile 
    213     #delete_ArbreFile(doc_file) 
    214      
    215      
    216     data=data_for_product(product) 
    217  
    218     fileName, fileExtension = os.path.splitext(doc_file.filename)  
    219     new_ArbreFile= ArbreFile(decomposable=bool(product.links)) 
    220     new_ArbreFile.stp = doc_file 
    221     name = new_ArbreFile.file.storage.get_available_name(fileName+".arb") 
    222     path = os.path.join(new_ArbreFile.file.storage.location, name) 
    223     new_ArbreFile.file = name 
    224     new_ArbreFile.save() 
    225     directory = os.path.dirname(path.encode())         
    226     if not os.path.exists(directory): 
    227         os.makedirs(directory) 
    228     output = open(path.encode(),"w") 
    229     output.write(json.dumps(data))         
    230     output.close()  
    231     return new_ArbreFile.file.path           
    232     
    233      
    234      
    235                  
    236   
    237      
    238     
    239  
    240        
     125        
    241126def function_generate_menu(numeration,name): 
    242127 
     
    270155 
    271156 
    272 #var NewMaterial=new THREE.MeshFaceMaterial({opacity:0.5,shading:THREE.SmoothShading}); 
    273157   
    274158     
  • trunk/openPLM/document3D/classes.py

    r1009 r1022  
    3131 
    3232class Product(object): 
    33  
     33    """ 
     34    Class used to represent the **arborescense** contained in a :class:`~django.core.files.File` **.stp**.A :class:`.Product` can be simple or an assembly, if it is an assembly in **links** we will guard the information about other :class:`.Product` that compose it 
     35     
     36    :model attributes: 
     37 
     38    .. attribute:: links 
     39              
     40        If the product is an assembly, links stores one or more :class:`.openPLM.document3D.classes.Link` references to the products that compose it    
     41 
     42 
     43    .. attribute:: label_reference 
     44     
     45        When we generate an arborescense using pythonOCC, here we will store the label that represents the :class:`.Product` ,if we generate the arborescense reading a file **.geo**, this attribute will be **False** 
     46         
     47    .. attribute:: name 
     48     
     49        Name of :class:`.Product` ,if the name is empty and there exists a :class:`.Link` at the :class:`.Product` , we will assign the name of the :class:`.Link` to the :class:`.Product` 
     50         
     51    .. attribute:: doc_id 
     52     
     53        Id of the :class:`.DocumentFile` that contains the :class:`.Product` , in the case of :class:`~django.core.files.File` .stp decomposed them **doc_id** maybe different for every :class:`.Product` of the arborescense     
     54         
     55    .. attribute:: doc_path 
     56     
     57        Path of the :class:`~django.core.files.File` represented by the :class:`.DocumentFile` that contains the product    
     58         
     59    .. attribute:: part_to_decompose 
     60     
     61        Used in the decomposition, it indicates the :class:`.Part` where the :class:`.Product` was decomposed 
     62 
     63    .. attribute:: geometry 
     64     
     65        If geometry is True (>=1) then the :class:`.Product` is single (without **links** )  , and his value refers to the index that we will use to recover a :class:`.GeometryFile`           
     66         
     67    .. attribute:: deep 
     68     
     69        Depth in the arborescense   
     70         
     71    .. attribute:: visited 
     72     
     73        Used in the decomposition , indicates if a :class:`.Product`  has been visited in the tour of the arborescense 
     74               
     75    """ 
    3476    __slots__ = ("label_reference","name","doc_id","links","geometry","deep","doc_path","visited","part_to_decompose") 
    3577     
    3678     
    37     def __init__(self,name,deep,label_reference,doc_id,doc_path=None,geometry=None): 
     79    def __init__(self,name,deep,label_reference,doc_id,doc_path=None,geometry=False): 
    3880        #no tiene location 
    39         self.links = [] 
     81        self.links = []           
    4082        self.label_reference=label_reference 
     83        #if name="": 
     84            #raise "Must we forbid it?"   
    4185        self.name=name 
    4286        self.doc_id=doc_id 
    43         self.doc_path=doc_path # indica tmb si el elemento ya ha sido descompuesto 
     87        self.doc_path=doc_path  
    4488        self.part_to_decompose=False 
    45         self.geometry=geometry 
     89        self.geometry=geometry  
    4690        self.deep=deep 
    4791        self.visited=False 
    4892    def set_geometry(self,geometry): 
    49         self.geometry=geometry 
     93        #0 cant be a valid geometry index , 0==False 
     94        if geometry: 
     95            self.geometry=geometry 
     96        else: 
     97            raise Document3D_generate_Index_Error 
    5098     
    5199         
    52100    @property        
    53101    def is_decomposed(self): 
     102        """ 
     103        If it is an assembly and the any :class:`.Product` contents in his **links**  are defined (**doc_id**) in another :class:`DocumentFile` (**doc_id**) 
     104        """ 
    54105        for link in self.links: 
    55106            if not link.product.doc_id == self.doc_id: 
     107                return True  
     108        return False 
     109         
     110    @property        
     111    def is_decomposable(self): 
     112        """ 
     113        If it is an assembly and any :class:`.Product` contents in his **links** are defined (**doc_id**) in the same :class:`DocumentFile` (**doc_id**) 
     114        """ 
     115        for link in self.links: 
     116            if link.product.doc_id == self.doc_id: 
    56117                return True  
    57118        return False 
     
    60121        if self.links: 
    61122            return self.name  
    62         return False  
     123        return False 
     124         
     125  
     126          
    63127class Link(object): 
    64  
     128    """ 
     129     
     130    Class used to represent a :class:`Link` between a :class:`.Product`, a :class:`Link` can have several references, each one with his own name and matrix of transformation. Every :class:`Link` points at a :class:`.Product` 
     131 
     132     
     133     
     134     
     135    :model attributes: 
     136         
     137         
     138    .. attribute:: names 
     139     
     140        Name of each instances of the :class:`Link` , if the instance does not have name, he get the name of his :class:`.Product` child  
     141 
     142    .. attribute:: locations 
     143     
     144        :class:`Matrix_rotation` of each instances of the :class:`Link`  
     145                
     146    .. attribute:: product 
     147     
     148        :class:`.Product` child of the :class:`Link` 
     149         
     150    .. attribute:: quantity 
     151     
     152        Number of instances of the :class:`Link`  (Every instance have a **name** and **location**) 
     153         
     154    .. attribute:: visited 
     155     
     156        Used in the decomposition , indicates if a :class:`Link` has been visited in the tour of the arborescense   
     157     
     158    """     
    65159    __slots__ = ("names","locations","product","quantity","visited") 
    66160     
    67      
     161 
    68162    def __init__(self,product): 
    69163   
     
    90184         
    91185class Matrix_rotation(object): 
    92  
     186    """ 
     187     
     188    Defines a non-persistent transformation in 3D space 
     189          
     190     == == == == == = == 
     191     x1 x2 x3 x4  x = x'     
     192     y1 y2 y3 y4  y = y'     
     193     z1 z2 z3 z4  z = z'     
     194     0  0  0  1   1 = 1   
     195     == == == == == = == 
     196      
     197     
     198    """ 
    93199    __slots__ = ("x1","x2","x3","x4","y1","y2","y3","y4","z1","z2","z3","z4") 
    94      
     200 
    95201     
    96202    def __init__(self,list_coord): 
     
    110216            self.z4=list_coord[11]     
    111217 
    112     """     
    113     def Transformation(self): 
    114         transformation=gp_Trsf() 
    115         transformation.SetValues(self.x1,self.x2,self.x3,self.x4,self.y1,self.y2,self.y3,self.y4,self.z1,self.z2,self.z3,self.z4,1,1) 
    116         return transformation      
    117     """           
     218    
    118219    def to_array(self):     
    119220        return [self.x1,self.x2,self.x3,self.x4,self.y1,self.y2,self.y3,self.y4,self.z1,self.z2,self.z3,self.z4]  
     
    121222 
    122223 
    123  
    124 def generateArbre(arbre,product=False,product_root=False,deep=0,from_child_ArbreFile=False):    
     224def Product_from_Arb(arbre,product=False,product_root=False,deep=0,to_update_product_root=False):    
     225 
     226    """  
     227     
     228    :param arbre: chain of characters formatted (following the criteria of the function :class:`.data_for_product`) that represents an arborescense,It contains necessary information to construct :class:`.Product` and :class:`Link`  
     229 
     230    :param product: Product that represents a arborescense , **ONLY** used in successive recursive calls of the function 
     231    :type plmobject: :class:`.Product` 
     232    :param product_root: Product that represents a root arborescense , used to determine if the product to generating is already present in the tree  
     233    :type plmobject: :class:`.Product` 
     234    :param deep: depth of **product** in the arborescense 
     235    :param to_update_product_root: Product that represents a node of an arborescense  (sub-brach of arborescense referenced by **product_root**) 
     236    :type plmobject: :class:`.Product` 
     237         
     238     
     239    
     240     
     241    From the information contained in a file **.arb** (**arbre**), it generates the corresponding :class:`Product` 
     242    In case of files STEP decomposed, this information can be distributed in several files **.arb** and due to the  
     243    nature of the decomposition, a **product** could be generated more than once , to avoid this we use the **product_root**. 
     244    Whenever we generate a new product we verify that it is not already present in **product_root**,we use **to_update_product_root**  
     245    to support updated **product_root**(**to_update_product_root** is a branch of **product_root**) 
     246     
     247    Example: 
     248        -If we want to generate a **product** of a single file **.arb** 
     249            tree =Product_from_Arb(json.loads(new_ArbreFile.file.read())) 
     250             
     251             
     252        -If we want to generate a **product** of a single file .arb and link this one like a branch of a certain **product_root_node** of an already existing **product_root** 
     253          
     254            product=Product_from_Arb(json.loads(new_ArbreFile.file.read()),product=False, product_root=product_root, deep=xxx, to_update_product_root=product_root_node) 
     255              
     256            This method generates the :class:`Link` between **product_root_node** and  **product** ,**BUT** it does not add the occurrences, generally this occurrences are stored in the  
     257            existing  :class:`Location_link` between :class:`Part` 
     258             
     259                After generating the **product** and the :class:`Link`, we will have to refill the :class:`Link` calling the function :meth:`.add_occurrence` for the :class:`Link`: 
     260                 
     261                 
     262                    for location in locations: 
     263                        product_root_node.links[-1].add_occurrence(location.name,location) 
     264     
     265     
     266    """ 
    125267    label_reference=False 
    126  
    127  
    128            
    129     if not product_root: 
    130         product=generate_product(arbre,deep) 
     268                  
     269    if not product_root:  
     270        product=generateProduct(arbre,deep) 
    131271        product_root=product 
    132     elif from_child_ArbreFile: 
    133         product=generate_product(arbre,deep) 
     272         
     273         
     274    elif to_update_product_root: #Important, in case of generation of a tree contained in several files, it supports updated product_root 
     275        product=generateProduct(arbre,deep) 
    134276        product_assembly=search_assembly(product.name,label_reference,product.doc_id,product_root,product.geometry) 
    135277        if product_assembly:  
    136             from_child_ArbreFile.links.append(Link(product_assembly)) 
     278            to_update_product_root.links.append(Link(product_assembly)) 
    137279            return False  
    138280        else: 
    139             from_child_ArbreFile.links.append(Link(product))  
    140            
     281            to_update_product_root.links.append(Link(product))  
     282               
    141283                     
    142284    for i in range(len(arbre)-1): 
    143285         
    144         product_child=generate_product(arbre[i+1][1],deep+1) 
     286        product_child=generateProduct(arbre[i+1][1],deep+1) 
    145287        product_assembly=search_assembly(product_child.name,label_reference,product_child.doc_id,product_root,product_child.geometry) 
    146288 
     
    148290        if product_assembly: 
    149291            product_child=product_assembly  
     292             
     293            
    150294                                     
    151         generate_link(arbre[i+1],product,product_child)  
     295        generateLink(arbre[i+1],product,product_child)  
    152296                
    153297        if not product_assembly: 
    154             generateArbre(arbre[i+1][1],product_child,product_root,deep+1)   
     298            Product_from_Arb(arbre[i+1][1],product_child,product_root,deep+1)   
    155299             
    156300            
     
    159303 
    160304         
    161 def generate_link(arbre,product,product_child): 
     305def generateLink(arbre,product,product_child): 
     306    """  
     307    :param arbre: chain of characters formatted (following the criteria of the function :class:`.data_for_product`) that represents the different occurrences of a :class:`Link` 
     308    :param product: :class:`Product` root of the assembly  
     309    :param product_child: :class:`Product` child of the assembly  
     310     
     311    """ 
    162312    product.links.append(Link(product_child)) 
    163313    for i in range(len(arbre[0])): 
     
    165315         
    166316                  
    167 def generate_product(arbre,deep): 
     317def generateProduct(arbre,deep): 
     318    """  
     319    :param arbre: chain of characters formatted (following the criteria of the function :class:`.data_for_product`) that represents a :class:`Product`  
     320    :param deep: depth of :class:`Product` 
     321     
     322    """ 
    168323    label_reference=False 
    169324    return Product(arbre[0][0],deep,label_reference,arbre[0][1],arbre[0][3],arbre[0][2])    
     
    172327 
    173328 
    174 def search_assembly(name,label,id,product_root,geometry=False): # 2 modos , con geometrias y sin geometrias, si hay labels o si no las hay 
    175  
     329def search_assembly(name,label,doc_id,product_root,geometry):  
     330    """ 
     331     
     332    :param product_root: :class:`Product` that represents a root arborescense   
     333    :type plmobject: :class:`.Product` 
     334    :param geometry: indicates if the :class:`Product` for that we look is a Assembly (**product.geometry** is False )or a simple :class:`Product` (**product.geometry** >=1) 
     335    :param name: name of :class:`Product` for that we look 
     336    :param doc_id: id of :class:`.DocumentFile` that contains the :class:`Product` for that we look 
     337    :param label: label generated by pythonOCC that represent the :class:`Product` for that we look 
     338          
     339    Function that it checks if a :class:`Product` (determined by **name** , **id** and **geometry** or by **name** and **label**)is already present in a arborescense :class:`Product` (**product_root**) 
     340    There are two manners of comparison, across **name** and **label_referencia**, generated for pythonOCC for every product, or across **name**, **doc_id** and **geometry** ,extracted of a file **.geo** 
     341    """ 
    176342   
    177343    if product_root:  
    178344        for link in product_root.links: 
    179345 
    180                  
    181             if name and link.product.name==name: 
    182                              
     346            if (name and link.product.name==name and   
     347            ((geometry and link.product.geometry) or (not geometry and not link.product.geometry))):# 2 assemblys or 2 geometrys wtih same name        
     348                                 
    183349                if label: 
    184  
     350                     
    185351                    if link.product.label_reference==label: 
    186352                        return link.product 
    187353                     
    188                 elif id==link.product.doc_id and geometry==link.product.geometry: 
     354                     
     355                elif doc_id==link.product.doc_id and geometry==link.product.geometry: 
    189356                    return link.product                                         
    190  
    191                 #else: 
    192                     #pass 
    193                     #raise "FATAL ERROR , 2 assembly diferente shape , FATAL FATALTALTALTALTATLA" 
    194                  
    195             else: 
    196   
    197                 product=search_assembly(name,label,id,link.product,geometry) 
    198                 if product: 
    199                     return product 
    200  
    201      
    202 def getMatrixFromLocation(Location): 
    203  
    204  
    205     m=Location.VectorialPart() 
    206     gp=m.Row(1) 
    207     x1=gp.X()            
    208     x2=gp.Y() 
    209     x3=gp.Z() 
    210     x4=Location.Transforms()[0] 
    211     gp=m.Row(2) 
    212     y1=gp.X()           
    213     y2=gp.Y() 
    214     y3=gp.Z() 
    215     y4=Location.Transforms()[1] 
    216     gp=m.Row(3) 
    217     z1=gp.X()          
    218     z2=gp.Y() 
    219     z3=gp.Z() 
    220     z4=Location.Transforms()[2]    
    221     return [x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4]      
     357                     
     358         
     359                #raise "2 diferent assembly or geometrys with same name" #is not recomndable to had 2 product or 2 assembly whit same name 
     360 
     361                     
     362 
     363      
     364            product=search_assembly(name,label,doc_id,link.product,geometry) 
     365            if product: 
     366                return product 
     367 
     368     
     369    
    222370     
    223371             
    224372def data_for_product(product): 
     373    """ 
     374    :param product: :class:`Product` for which the chain was generated 
     375     
     376    generate a chain of characters formatted that contains information about a :class:`Product` 
     377     
     378    """ 
    225379    output=[] 
    226380 
     
    233387                
    234388def data_for_link(link): 
    235  
    236      
     389    """ 
     390    :param product: :class:`Link` for which the chain was generated 
     391     
     392    generate a chain of characters formatted that contains information about a :class:`Link` 
     393     
     394    """     
    237395    output=[]     
    238396    name_loc=[] 
  • trunk/openPLM/document3D/generate3D.py

    r977 r1022  
    22import os 
    33from classes import data_for_product , get_available_name 
    4 from STP_converter_WebGL import NEW_STEP_Import 
     4from STP_converter_WebGL import NEW_STEP_Import , MultiRoot_Error , OCC_ReadingStep_Error  
    55import logging 
    66import django.utils.simplejson as json 
     
    88 
    99 
     10def generateGeometrys_Arborescense(doc_file_path,doc_file_id,location): 
     11    """ 
     12    For a file STEP determined by his path, it generates his file .arb and his files .geo 
     13    """  
     14    logging.getLogger("GarbageCollector").setLevel(logging.ERROR)     
     15    my_step_importer = NEW_STEP_Import(doc_file_path,doc_file_id)  
     16    product_arbre=my_step_importer.generate_product_arbre()    
     17    geo=my_step_importer.procesing_geometrys(location) 
     18    print geo 
     19    print write_ArbreFile(product_arbre,my_step_importer.fileName,location) 
    1020 
    11 def generateGeometry(doc_file_path,doc_file_id,location): 
    12  
    13     logging.getLogger("GarbageCollector").setLevel(logging.ERROR) 
    14     my_step_importer = NEW_STEP_Import(doc_file_path,doc_file_id) 
    15     print my_step_importer.procesing_geometrys(location) 
    16     product_arbre=my_step_importer.generate_product_arbre() 
    17     print write_ArbreFile(product_arbre,my_step_importer.fileName,location) 
    1821 
    1922 
     
    3336    output.write(json.dumps(data))         
    3437    output.close()  
    35     decomposable = "true" if product.links and not product.is_decomposed else "false" 
     38    decomposable = "true" if product.links and product.is_decomposable else "false" 
    3639    return "ARB:%s\nDecomposable:%s\n" % (name, decomposable)  
    3740     
     41try:     
     42    generateGeometrys_Arborescense(sys.argv[1],sys.argv[2],sys.argv[3])         
     43except Exception as excep: 
     44    if type(excep)==MultiRoot_Error: 
     45        sys.exit(-1) 
     46    elif type(excep)==OCC_ReadingStep_Error: 
     47        sys.exit(-2) 
     48    sys.exit(-3) 
     49 
    3850     
    39 generateGeometry(sys.argv[1],sys.argv[2],sys.argv[3])             
    40  
  • trunk/openPLM/document3D/generateComposition.py

    r1007 r1022  
    99from OCC.gp import gp_Trsf 
    1010from STP_converter_WebGL import NEW_STEP_Import , SetLabelNom , colour_chercher 
    11 from classes import generateArbre 
    12  
     11from classes import Product_from_Arb 
     12from OCC.Quantity import Quantity_Color 
    1313 
    1414 
     
    2121     
    2222    output = open(temp_file_name.encode(),"r") 
    23     product =generateArbre(json.loads(output.read())) 
     23    product =Product_from_Arb(json.loads(output.read())) 
    2424    output.close() 
    2525    output = open(temp_file_name.encode(),"w+")# erase old data 
     
    5151def add_labels(product,lr,st): 
    5252 
    53      
    54     for link in product.links: 
     53    if product.links: 
     54        for link in product.links: 
    5555 
    56      
    57         if link.product.doc_id!= product.doc_id: # solo los que esten descompuesto, si no esta descompuesto no tiene que anadirlo 
     56         
     57            if link.product.doc_id!= product.doc_id: # solo los que esten descompuesto, si no esta descompuesto no tiene que anadirlo 
    5858 
    59             if not link.product.label_reference: 
     59                if not link.product.label_reference: 
    6060 
    61                 my_step_importer = NEW_STEP_Import(link.product.doc_path) 
    62                 lr_2= TDF_LabelSequence() 
    63                 my_step_importer.shape_tool.GetFreeShapes(lr_2)         
    64                 add_labels(link.product,lr_2.Value(1),my_step_importer.shape_tool) 
    65                 link.product.label_reference=lr_2.Value(1) 
    66                
    67                
    68             for d in range(link.quantity): 
     61                    my_step_importer = NEW_STEP_Import(link.product.doc_path) 
     62                    lr_2= TDF_LabelSequence() 
     63                    my_step_importer.shape_tool.GetFreeShapes(lr_2)         
     64                    add_labels(link.product,lr_2.Value(1),my_step_importer.shape_tool) 
     65                    link.product.label_reference=lr_2.Value(1) 
     66                     
     67                for d in range(link.quantity): 
    6968 
    70                 transformation=gp_Trsf() 
    71                 transformation.SetValues(link.locations[d].x1,link.locations[d].x2,link.locations[d].x3,link.locations[d].x4,link.locations[d].y1,link.locations[d].y2,link.locations[d].y3,link.locations[d].y4,link.locations[d].z1,link.locations[d].z2,link.locations[d].z3,link.locations[d].z4,1,1)   
    72                 new_label=st.AddComponent(lr,link.product.label_reference,TopLoc_Location(transformation)) 
    73                 SetLabelNom(new_label,link.names[d]) 
     69                    transformation=gp_Trsf() 
     70                     
     71                    transformation.SetValues(link.locations[d].x1,link.locations[d].x2,link.locations[d].x3,link.locations[d].x4, 
     72                    link.locations[d].y1,link.locations[d].y2,link.locations[d].y3,link.locations[d].y4,link.locations[d].z1,link.locations[d].z2, 
     73                    link.locations[d].z3,link.locations[d].z4,1,1)  
     74                      
     75                    new_label=st.AddComponent(lr,link.product.label_reference,TopLoc_Location(transformation)) 
     76                    SetLabelNom(new_label,link.names[d]) 
    7477 
    75              
    76         else: 
    77             pass # no hace falta por que ya esta en la geometria                                             
     78                 
     79            else: 
     80                pass # no hace falta por que ya esta en la geometria 
     81                                          
    7882                 
    7983     
  • trunk/openPLM/document3D/generateDecomposition.py

    r1005 r1022  
    88from STP_converter_WebGL import NEW_STEP_Import 
    99import django.utils.simplejson as json 
    10 from classes import generateArbre 
     10from classes import Product_from_Arb 
    1111from OCC.GarbageCollector import garbage 
    1212 
     
    2222 
    2323    output = open(temp_file_name.encode(),"r") 
    24     old_product=generateArbre(json.loads(output.read())) 
     24    old_product=Product_from_Arb(json.loads(output.read())) 
    2525    my_step_importer = NEW_STEP_Import(path) 
    2626    shape_tool=my_step_importer.shape_tool  
  • trunk/openPLM/document3D/mesh.py

    r973 r1022  
    5252    By default, this argument is set to 1 : the default precision of the mesher is used. 
    5353    ''' 
    54     #print "entro"  
    55     #garbage.smart_purge() 
    56     #print "salgo"    
     54 
    5755    quality_factor=0.3 
    5856    a_mesh = QuickTriangleMesh(shape.shape,quality_factor) 
     
    8684    def __init__(self,shape,quality_factor): 
    8785        self._shape = shape 
    88         #self._shape.was_purged 
     86 
    8987        bbox = Bnd_Box() 
    9088        BRepBndLib_Add(self._shape, bbox)  
  • trunk/openPLM/document3D/models.py

    r1009 r1022  
    55from openPLM.plmapp.controllers import DocumentController 
    66from openPLM.plmapp.models import * 
     7from openPLM.plmapp.controllers.part import PartController 
    78from django.db.models import Q 
    89from openPLM.document3D.classes import * 
    9 from openPLM.document3D.arborescense import * 
    1010import subprocess 
    1111import tempfile 
     
    1515from openPLM.plmapp.controllers import get_controller 
    1616import copy 
    17  
    18  
     17from celery.exceptions import TimeoutError 
     18 
     19#./manage.py graph_models document3D > models.dot   dot -Tpng models.dot > models.png 
    1920 
    2021 
     
    2324 
    2425class Document3D(Document): 
    25     """ 
    26     Model which allows to treat files STEP for his later visualization and decomposition. It extends :class:`Document` with the attribute/tab 3D     
    27     :model attributes: 
    28              
    29             :class:`Part` from which we generate the decomposition of the file STEP    
    30         .. attribute:: PartDecompose 
    31              
    32             original filename 
    33         .. attribute:: file 
    34              
    35             file stored in :obj:`docfs` 
    36         .. attribute:: size 
    37              
    38             size of the file in Byte 
    39         .. attribute:: locked 
    40  
    41             True if the file is locked 
    42         .. attribute:: locker 
    43              
    44             :class:`~django.contrib.auth.models.User` who locked the file, 
    45             None, if the file is not locked 
    46         .. attribute:: document 
    47  
    48             :class:`Document` bounded to the file (required) 
     26 
     27    u""" 
     28    Model which allows to treat :class:`~django.core.files.File` **.stp**  attached to  :class:`.DocumentFile` for his later **visualization** and **decomposition**. It extends :class:`.Document` with the attribute/tab 3D     
     29 
     30     .. attribute:: PartDecompose 
     31                 
     32            If the :class:`.Document3D` has been **decomposed** , :class:`.Part` from which we generate the **decomposition**  
     33 
     34                     
    4935    """ 
    5036 
     
    6450    def get_content_and_size(self, doc_file): 
    6551        """ 
    66         Returns one DocumentFile related to this Document3D. 
    67         If the DocumentFile was decomposed , this function calls a subprocess to reconstruct the file  
     52        :param doc_file: :class:`.DocumentFile` which contains the :class:`~django.core.files.File` 
     53        :type plmobject: :class:`.DocumentFile`  
     54                
     55        Returns the :class:`~django.core.files.File` related to the  :class:`.DocumentFile` (**doc_file**) and his *size* 
     56         
     57        If the :class:`~django.core.files.File` contains in the :class:`.DocumentFile` (**doc_file**) is a **.stp** and was *decomposed* , this function calls a subprocess( :meth:`.composer` ) to rebuild the .stp :class:`~django.core.files.File`  
    6858        """  
    6959        fileName, fileExtension = os.path.splitext(doc_file.filename) 
     
    7161             
    7262 
    73             product=read_ArbreFile(doc_file,recursif=True)# last True to generate arbre whit doc_file_path insteant doc_file_id 
     63            product=ArbreFile_to_Product(doc_file,recursif=True)# last True to generate arbre whit doc_file_path insteant doc_file_id 
    7464             
    7565            if product and product.is_decomposed: 
     
    8575                    raise Document3D_composition_Error  
    8676                 
    87             else: 
    88                 return super(Document3D, self).get_content_and_size(doc_file) 
    89              
    90             pass                 
    91         else: 
    92             return super(Document3D, self).get_content_and_size(doc_file) 
     77 
     78        return super(Document3D, self).get_content_and_size(doc_file) 
    9379 
    9480#admin.site.register(Document3D) 
    95  
    9681 
    9782 
     
    9984@task(soft_time_limit=60*25,time_limit=60*25) 
    10085def handle_step_file(doc_file_pk): 
    101  
    102     """ 
    103     Method called when adding a file STEP (method :meth:`add_file`) into Document3D with 
    104     *updates_attributes* true. 
    105  
    106     It calls the subprocess generate3D, that generates and associates an ArbreFile and one o more GeometryFiles with the documentFile 
    107      
    108  
    109     """ 
    110  
    111  
     86    """ 
     87     
     88    :param doc_file_pk: primery key of a :class:`.DocumentFile` that will be treated 
     89      
     90    Method called when adding :class:`~django.core.files.File` **.stp** (:meth:`.add_file` with  *updates_attributes* true) into :class:`.Document3DController`. 
     91 
     92    It calls a subprocess (:meth:`.generateGeometrys_Arborescense` ) that generates an file **.arb** and one or more files **.geo** (these files  
     93    are necessary for the visualization 3D and the decomposition of the :class:`~django.core.files.File` **.stp** ),  
     94    later this files will be attached to an :class:`.ArbreFile` and one or more :class:`.GeometryFile` and these classes with the :class:`.DocumentFile` determined by **doc_file_pk**      
     95 
     96    """ 
    11297    import logging 
    11398    logging.getLogger("GarbageCollector").setLevel(logging.ERROR) 
     
    115100    temp_file = tempfile.TemporaryFile() 
    116101    stdout = temp_file.fileno() 
    117     if subprocess.call(["python", "document3D/generate3D.py",doc_file.file.path,str(doc_file.id),settings.MEDIA_ROOT+"3D/"],stdout=stdout) == 0: 
    118         delete_ArbreFile(doc_file) 
     102    status=subprocess.call(["python", "document3D/generate3D.py",doc_file.file.path,str(doc_file.id),settings.MEDIA_ROOT+"3D/"],stdout=stdout) 
     103    if status == 0: 
     104        """ 
     105        The subprocess is going to return a temporary file with the names of the files *.geo* and *.arb* generated.  
     106        In the moment of his generation these files are not associated the documentFile 
     107        """ 
     108        delete_ArbreFile(doc_file) #In case of an update, to erase the previous elements 
    119109        delete_GeometryFiles(doc_file) 
    120         generate_relations_BD(doc_file,stdout,temp_file) 
    121  
     110        generate_relations_BD(doc_file,temp_file)# We associate the files generated to classes and the classes to the documentFile 
     111 
     112    elif status == -1: 
     113        #MultiRoot_Error  SEND MAIL? 
     114        raise ValueError("OpenPLM does not support files STEP with multiple roots") 
     115    elif status == -2: 
     116        #OCC_ReadingStep_Error SEND MAIL? 
     117        raise ValueError("PythonOCC could not read the file") 
    122118    else: 
    123         raise Document3D_link_Error 
    124         pass 
    125  
    126      
    127      
    128      
    129  
    130          
    131 def generate_relations_BD(doc_file,stdout,temp_file):               
    132               
     119        #Indeterminate error SEND MAIL? 
     120        raise ValueError("Error during the treatment of the file STEP")         
     121 
     122 
     123     
     124     
     125     
     126 
     127         
     128def generate_relations_BD(doc_file,temp_file): 
     129    """ 
     130    Function used when we add a new :class:`~django.core.files.File` **.stp** in a :class:`.Document3D`  
     131    This function associates a series of files with classes :class:`.ArbreFile` and :class:`.GeometryFile`  
     132    and this classes to a :class:`.DocumentFile`. The files was generated before the call to this function,  
     133    his path are known thanks to the information supplied in the temporary file(Every line of this file represents  
     134    a file, the beginning of every line indicates the type of file) 
     135     
     136    :param doc_file: object which will be updated 
     137    :type plmobject: :class:`.DocumentFile` 
     138    :param temp_file: :class:`.tempfile` that contains the path of the generated **.geo** and **.arb** files 
     139    :type plmobject: :class:`.tempfile` 
     140    """                   
     141    stdout = temp_file.fileno()      
    133142    os.lseek(stdout, 0, 0) 
    134143    arb = None 
     
    148157 
    149158 
    150 def generateGeometry(name_index,doc_file): 
    151  
     159def generateGeometry(name_path,doc_file): 
     160    """ 
     161    The function receives a path of file(**name_path[0]**) **.geo** and an index(**name_path[1]**), generates a new entity   
     162    :class:`.GeometryFile` and associates this class to the :class:`.DocumentFile` (**doc_file**) spent as parameter 
     163     
     164    :param doc_file: :class:`.DocumentFile` which will be attached to the :class:`.GeometryFile` 
     165    :type plmobject: :class:`.DocumentFile` 
     166    :param name_index: index(name_path[1]) and path(name_path[0]) to identify the geometry of the file **.geo** (**>=1**) 
     167    """ 
    152168    new_GeometryFile= GeometryFile() 
    153169    new_GeometryFile.stp = doc_file 
    154     new_GeometryFile.file = name_index[0] 
    155     new_GeometryFile.index = name_index[1] 
     170    new_GeometryFile.file = name_path[0] 
     171    new_GeometryFile.index = name_path[1] 
    156172    new_GeometryFile.save() 
    157173 
    158 def generateArborescense(name, doc_file, decomposable): 
    159  
     174def generateArborescense(path, doc_file, decomposable): 
     175    """ 
     176    The function receives a path of file(**path**) of a file **.arb**, generates a new entity of the class  
     177    :class:`.ArbreFile` and associates this class to the :class:`.DocumentFile` (**doc_file**) spent as parameter, 
     178    it initializes the attribute decomposable of generated entity (whit the value **decomposable**),  
     179    this attribute indicates if the :class:`.DocumentFile` can be decompose 
     180     
     181    :param doc_file: object which will be attached to the :class:`.ArbreFile` 
     182    :type plmobject: :class:`.DocumentFile` 
     183    :param path: path of the file **.arb** 
     184    :param decomposable: boolean that determines if the file can be decomposed 
     185    """ 
    160186    new_ArbreFile= ArbreFile() 
    161187    new_ArbreFile.stp = doc_file 
    162     new_ArbreFile.file = name 
     188    new_ArbreFile.file = path 
    163189    new_ArbreFile.decomposable = decomposable 
    164190    new_ArbreFile.save() 
    165191  
    166192 
    167 is_stp=Q(filename__iendswith=".stp") | Q(filename__iendswith=".step")  
     193is_stp=Q(filename__iendswith=".stp") | Q(filename__iendswith=".step")#.stp , .STP , .step , .STEP  
    168194 
    169195    
    170196class Document3DController(DocumentController): 
    171  
    172                    
    173       
    174                        
     197    """ 
     198    A :class:`DocumentController` which manages  
     199    :class:`.Document3D` 
     200     
     201    It provides methods to deprecate and to manage (**visualization3D** and **decomposition**)files STEP. 
     202    """ 
     203                     
    175204    def handle_added_file(self, doc_file): 
    176  
     205        """ 
     206        If a :class:`~django.core.files.File` .stp is set like the file of a :class:`.DocumentFile` (**doc_file**) added to a :class:`.Document3D` , a special treatment (:meth:`.handle_step_file`) is begun (Only one file STEP allowed for each :class:`.Document3D` )  
     207        """ 
    177208        fileName, fileExtension = os.path.splitext(doc_file.filename) 
    178209                       
     
    181212                self.delete_file(doc_file) 
    182213                raise ValueError("Only one step documentfile allowed for each document3D")  
    183             handle_step_file.delay(doc_file.pk) 
    184             #handle_step_file(doc_file.pk)     
     214                 
     215            try: 
     216                #handle_step_file.delay(doc_file.pk)#It generates entitys ArbreFile and Geometry and associates this classes to the documentFile 
     217                handle_step_file.delay(doc_file.pk) 
     218            except Exception as excep: 
     219                 
     220                if type(excep)==TimeoutError: 
     221                    #TimeoutError SEND MAIL?  
     222                    raise excep 
     223                else: 
     224                    #Indeterminate error SEND MAIL? 
     225                    raise excep     
     226                 
     227 
     228              
    185229               
    186230         
    187231                     
    188232    def delete_file(self, doc_file): 
    189      
     233        """ 
     234        We erase also the classes :class:`.GeometryFile` and :class:`.ArbreFile` associated with the :class:`.DocumentFile` (**doc_file**) 
     235        """ 
    190236        fileName, fileExtension = os.path.splitext(doc_file.filename) 
    191237 
     
    199245 
    200246    def deprecate_file(self, doc_file,by_decomposition=False): 
    201      
    202      
    203      
     247        """ 
     248        A file can be depreciated for diverse motives, (when a file STEP is decomposed,  
     249        when exists a native file associate to one file STEP and we realize a brute check-out of the STEP , the native will be deprecated , ...) 
     250         
     251        :param doc_file: :class:`.DocumentFile` which will be deprecated 
     252             
     253             
     254        """     
    204255        self.check_permission("owner") 
    205256        self.check_editable() 
     
    211262            self._save_histo("File deprecated for decomposition", "file : %s" % doc_file.filename)            
    212263        else: 
    213             self._save_histo("File deprecated", "file : %s" % doc_file.filename)     
     264            self._save_histo("File deprecated", "file : %s" % doc_file.filename)  
     265             
     266                
    214267media3DGeometryFile = DocumentStorage(location=settings.MEDIA_ROOT+"3D/")       
    215268class GeometryFile(models.Model): 
    216269    u""" 
    217     Link between file STEP present in a Document3D and  files .js that represents his geometries   1..* 
     270     
     271    Link between :class:`.DocumentFile` that contains a :class:`~django.core.files.File` **.stp** present in a :class:`.Document3D` and a file **.geo** that represents his geometry 
     272    A :class:`.DocumentFile` can have zero or many :class:`.GeometryFile` associated , to identify the different :class:`.GeometryFile` attached to one :class:`.DocumentFile` we use the 
     273    attribute index. (**index** should be **>=1**) 
     274     
     275    The information contained in the file **.geo** will allow to generate the  3D view of the :class:`.DocumentFile` 
     276     
     277     
     278     .. attribute:: stp 
     279      
     280        :class:`.DocumentFile` of relation 
     281         
     282     .. attribute:: file 
     283      
     284        file **.geo** 
     285             
     286     .. attribute:: index 
     287      
     288        to identify the different :class:`.GeometryFile` attached to one :class:`.DocumentFile`  (>=1) 
     289            
    218290    """ 
    219291    file = models.FileField(upload_to='.',storage=media3DGeometryFile) 
     
    232304    to_delete=GeometryFile.objects.filter(stp=doc_file)  
    233305    list_files=list(to_delete.values_list("file", flat=True)) 
    234     delete_files(list_files,media3DGeometryFile.location+"/") 
     306    delete_files(list_files,media3DGeometryFile.location) 
    235307    to_delete.delete() 
    236308     
     
    240312#admin.site.register(ArbreFile) 
    241313class ArbreFile(models.Model): 
     314    u""" 
     315    Link between :class:`.DocumentFile` that contains a :class:`~django.core.files.File` **.stp** present in a :class:`.Document3D` and  a file **.arb** that represents his arborescense 
     316    A :class:`.DocumentFile` STEP have one :class:`.ArbreFile` associated 
     317     
     318    The information contained in the file **.arb** will allow to generate the  3D view and the decomposition of the :class:`.DocumentFile`  
     319     
     320 
     321     
     322     
     323     .. attribute:: stp 
     324      
     325        :class:`.DocumentFile` of relation 
     326         
     327     .. attribute:: file 
     328      
     329        :class:`~django.core.files.File` **.arb** 
     330             
     331     .. attribute:: decomposable 
     332      
     333        this attribute indicates if the :class:`.DocumentFile` can be decompose 
     334    """ 
    242335    file = models.FileField(upload_to='.',storage=media3DArbreFile) 
    243336    stp = models.ForeignKey(DocumentFile) 
     
    249342    to_delete=ArbreFile.objects.filter(stp=doc_file)  
    250343    list_files=list(to_delete.values_list("file", flat=True)) 
    251     delete_files(list_files,media3DArbreFile.location+"/") 
     344    delete_files(list_files,media3DArbreFile.location) 
    252345    to_delete.delete()    
    253346     
    254 def delete_files(list_files,ext=""): 
     347def delete_files(list_files,location=""): 
    255348    for name in list_files: 
    256         filename=ext+name 
     349        filename = os.path.join(location, name) 
    257350        if os.path.exists(filename) and os.path.isfile(filename): 
    258351            os.remove(filename) 
     
    267360        return u"Error during the composition of the file" 
    268361         
    269                
     362class Document3D_generate_Error(Exception): 
     363    def __unicode__(self): 
     364        return u"Error during the generation of the ArbreFile and GeometryFiles"         
     365class Document3D_generate_Index_Error(Exception): 
     366    def __unicode__(self): 
     367        return u"Error , try to assign an index not validate for a geometry"                
    270368class Document3D_decomposer_Error(Exception): 
    271     def __init__(self, to_delete=None):   
    272         self.to_delete=to_delete 
     369     
    273370    def __unicode__(self): 
    274371        return u"Error while the file step was decomposed" 
    275          
    276 class Document_part_doc_links_Error(Exception): 
     372 
     373         
     374class Document_Generate_Bom_Error(Exception): 
    277375    def __init__(self, to_delete=None,assembly=None): 
    278         self.to_delete=to_delete 
     376        self.to_delete=to_delete# DocumentFiles generated 
    279377        self.assembly=assembly     
    280378    def __unicode__(self): 
    281         return u"Columns reference, type, revision are not unique "+self.assembly          
     379        return u"Columns reference, type, revision are not unique between the products of the assembly"+self.assembly #meter referencia          
    282380         
    283381 
    284382 
    285383class Location_link(ParentChildLinkExtension): 
    286     #redefinir el garbage collector 
     384    """ 
     385    Extend :class:`.ParentChildLinkExtension`  
     386    Represents the matrix of transformation (rotation and translation) and the name of one relation between assemblys. 
     387    When a file STEP is decomposed in Parts a :class:`.ParentChildLink` is generated between the Parts  
     388    and each of these :class:`.ParentChildLink` could have attached one o more :class:`.Location_link` 
     389 
     390    Defines a non-persistent transformation in 3D space      
     391 
     392    
     393     == == == == == = == 
     394     x1 x2 x3 x4  x = x'     
     395     y1 y2 y3 y4  y = y'     
     396     z1 z2 z3 z4  z = z'     
     397     0  0  0  1   1 = 1   
     398     == == == == == = == 
     399    """ 
    287400    x1=models.FloatField(default=lambda: 0)           
    288401    x2=models.FloatField(default=lambda: 0)  
     
    300413    name=models.CharField(max_length=100,default="no_name")     
    301414 
    302     """                
    303     def Transforms(self): 
    304      
    305         transformation=gp_Trsf() 
    306         transformation.SetValues(self.x1,self.x2,self.x3,self.x4,self.y1,self.y2,self.y3,self.y4,self.z1,self.z2,self.z3,self.z4,1,1) 
    307         return transformation 
    308     """ 
    309415               
    310416    def to_array(self):     
     
    341447register_PCLE(Location_link) 
    342448 
     449 
    343450def generate_extra_location_links(link,ParentChildLink): 
    344  
    345  
     451    """ 
     452    For a :class:`.ParentChildLink`, it generates the whole necessary :class:`Location_link` 
     453     
     454     
     455    :param link: :class:`.openPLM.document3D.classes.Link` which will be used to generated extra :class:`.Location_link`  
     456    :type plmobject: :class:`.Link` 
     457    :param ParentChildLink: :class:`.ParentChildLink` for that the extra :class:`Location_link` are generated 
     458    :type plmobject: :class:`.ParentChildLink` 
     459 
     460    """ 
    346461    for i in range(link.quantity): 
    347462        loc=Location_link() 
     
    375490     
    376491      
     492 
     493 
     494 
     495 
     496from celery.task import task 
    377497@task(soft_time_limit=60*25,time_limit=60*25) 
    378 def decomposer_all(stp_file_pk,old_product,part_pk,native_related_pk,user_pk): 
    379 #old product debe estar actualizado con los path de los ghots y las id 
    380 #IMPORTANTE, si quiero limpiar en caso de fallo necesito meter en product la id de la parte para asi poder eliminar los links 
    381      
     498def decomposer_all(stp_file_pk,arbre,part_pk,native_related_pk,user_pk): 
     499    """ 
     500     
     501    :param arbre: Information contained in file **.arb** that allows to generate a :class:`.Product` that represents the arborescense of the :class:`~django.core.files.File` .stp to decompose 
     502    :type plmobject: :class:`.Product` 
     503    :param stp_file_pk: primery key of a :class:`.DocumentFile` that contains the :class:`~django.core.files.File` that will be decompose 
     504    :param part_pk: primery key of a :class:`.Part` attached to the :class:`.Document3D` that contains the :class:`.DocumentFile` that will be decompose 
     505    :param native_related_pk: If exists a native file related to the :class:`.DocumentFile` that will be decompose ,  contains the primery key of the :class:`.DocumentFile` related to the native file  
     506     
     507     
     508    This function departs from a :class:`.DocumentFile` (**stp_file_pk**) associated with a :class:`.Document3D` attached to a :class:`.Part` (part_pk) and from  
     509    the :class:`.Product` related to the :class:`.DocumentFile` in order to decompose :class:`~django.core.files.File` .stp.With this purpose it realizes a call to the subprocess  
     510    :meth:`.generateDecomposition.py`. 
     511 
     512         
     513     
     514    -**Preconditions** ,before calling to this function, the following steps must have been realized: 
     515     
     516        -The bomb-child of Parts (in relation to the :class:`.Product` (generate across the **arbre**)) has been generated 
     517         
     518        -For every :class:`.ParentChildLink` generated in the previous condition we attach all the :class:`.location_link` relatives 
     519         
     520        -To every generated :class:`.Part` a :class:`.Document3D` has been attached and the :class:`.Document3D` as been set like the attribute PartDecompose of the :class:`.Part`  
     521         
     522        -The attribute doc_id of every node of the :class:`.Product` (generate across the **arbre**) is now the relative id of :class:`.Document3D` generated in the previous condition 
     523         
     524        -To every generated :class:`.Document3D` has been added a new empty(locked) :class:`.DocumentFile` .stp 
     525         
     526        -The attribute doc_path of every node of the :class:`.Product` is now the path of :class:`.DocumentFile` generated in the previous condition 
     527         
     528        -The :class:`.DocumentFile` (**stp_file_pk**) is locked 
     529         
     530        -If exists a :class:`.DocumentFile` native (**native_related_pk**) related to the :class:`.DocumentFile` (**stp_file_pk**), then this one was depreciated (afterwards will be promoted) 
     531 
     532         
     533      
     534 
     535    -**Treatment** 
     536     
     537         
     538        -The subprocess  :meth:`.generateDecomposition.py` is going to write in to doc_path of every node of the :class:`.Product` (generate across the **arbre**) the corresponding decomposed file              
     539    
     540      
     541    -**Postconditions** 
     542     
     543        -For every generated :class:`.Document3D` , the new :class:`.DocumentFile` added is unlocked 
     544         
     545        -For every new :class:`.DocumentFile` , his :class:`.GeometryFile` and :class:`.ArbreFile` have been generated  
     546         
     547        -The root :class:`.DocumentFile` (**stp_file_pk**) has been deprecated and unlocked 
     548         
     549        -A new root :class:`.DocumentFile` has been generated acording to the situation 
     550         
     551        -If exists a :class:`.DocumentFile` native (**native_related_pk**) related to the :class:`.DocumentFile` (**stp_file_pk**), then this one was promoted  
     552 
     553    """        
    382554    try: 
    383555        stp_file = DocumentFile.objects.get(pk=stp_file_pk) 
     
    386558        ctrl=ctrl(stp_file.document,user) 
    387559         
    388         product=generateArbre(json.loads(old_product))    
     560        product=Product_from_Arb(json.loads(arbre))    
    389561 
    390562        new_stp_file=DocumentFile() 
     
    401573        temp_file.seek(0)    
    402574        if subprocess.call(["python", "document3D/generateDecomposition.py",stp_file.file.path,temp_file.name]) == 0: 
    403             #el id del root del old procduct tiene que seguir apuntando a a lo antiguao para actualizar los geo.js 
    404575            update_child_files_BD(product,user,product.doc_id)  
    405576            update_root_BD(new_stp_file,stp_file,ctrl,product,f,name,part_pk) 
     
    407578        else: 
    408579 
    409             raise Document3D_link_Error       
    410      
    411     except Exception as excep: 
    412         print unicode(excep) 
    413         raise excep 
     580            raise Document3D_decomposer_Error       
     581     
     582    except: 
     583        raise Document3D_decomposer_Error 
    414584         
    415585    finally: 
     
    425595     
    426596     
    427 def update_root_BD(new_stp_file,stp_file,ctrl,product,f,name,part_pk): 
    428      
     597def update_root_BD(new_stp_file,stp_file,ctrl,product,file,name,part_pk): 
     598    """ 
     599     
     600    :param stp_file: :class:`.DocumentFile` that was decompose (will be deprecated) 
     601    :param new_stp_file: :class:`.DocumentFile` that will replace the :class:`.DocumentFile` that was decomposed  
     602    :param product: :class:`.Product` that represents the arborescense of the :class:`.DocumentFile` that was decompose 
     603    :param part_pk: primery key of a :class:`.Part` attached to the :class:`.Document3D` that contains the :class:`.DocumentFile` that was decomposed 
     604    :param ctrl: :class:`.Document3DController` that contains the :class:`.DocumentFile` that was decomposed 
     605    :param file: :class:`~django.core.files.File` that contains the new file .stp root 
     606    :param name: name for the :class:`.DocumentFile` (new_stp_file)  
     607    :type plmobject: :class:`.Product` 
     608     
     609     
     610     
     611    Updates a :class:`.DocumentFile` (**stp_file**) that was used like root in a decomposition , deprecating it and replacing by a new :class:`.DocumentFile` (**new_stp_file**) 
     612     
     613    This update consists in: 
     614     
     615        Connect the :class:`.DocumentFile` (**new_stp_file**) to the :class:`.Document3D` (**ctrl.object**) 
     616         
     617        Generate a new :class:`.ArbreFile` for the **new_stp_file** (**product**.doc_id and **product**.doc_path related to the **new_stp_file**) 
     618         
     619        Fix the attribute PartDecompose of the :class:`.Document3D` (**ctrl**.object) to the :class:`.Part` (**part_pk**)  
     620         
     621        Deprecate the :class:`.DocumentFile` (**stp_file**) 
     622         
     623    """     
    429624    new_stp_file.filename=product.name+".stp".encode("utf-8") 
    430625    new_stp_file.file=name 
    431     new_stp_file.size=f.size 
     626    new_stp_file.size=file.size 
    432627    new_stp_file.document=ctrl.object 
    433628    new_stp_file.save() 
     
    437632    product.doc_id=new_stp_file.id 
    438633    product.doc_path=new_stp_file.file.path 
    439     generate_ArbreFile(product,new_stp_file)      
     634    Product_to_ArbreFile(product,new_stp_file)      
    440635    ctrl.deprecate_file(stp_file,by_decomposition=True)                           
    441     Doc3D=Document3D.objects.get(id=ctrl.object.id) 
    442     Doc3D.PartDecompose=Part.objects.get(pk=part_pk) 
    443     Doc3D.save() 
     636 
    444637     
    445638def update_child_files_BD(product,user,old_id): 
    446  
    447     # 
     639    """ 
     640    :param product: :class:`.Product` that represents a sub-arborescense of the file step that was decompose 
     641    :param old_id: Identifies the :class:`.DocumentFile` root of the decomposition 
     642    :type plmobject: :class:`.Product` 
     643     
     644     
     645    Updates a :class:`.DocumentFile` STEP that WASNT root in a decomposition, to know which :class:`.DocumentFile` to update we use the attribute **product**.doc_id of the arborescense(**product**) 
     646     
     647    This update consists in: 
     648     
     649        Generate a new :class:`.ArbreFile` for each  :class:`.DocumentFile` STEP present in the arborescense(**product**) 
     650         
     651        Generate news :class:`.GeometryFile` for the :class:`.DocumentFile` STEP (Copies of the GeometryFiles of the root :class:`.DocumentFile` (Identified for **old_id**)) 
     652         
     653    """   
    448654         
    449655    for link in product.links: 
    450         if not link.product.visited: 
     656        if not link.product.visited: #only one time  
    451657            link.product.visited=True 
    452658            product_copy=copy.copy(link.product)   
     
    461667            product_copy.links=[] 
    462668            update_geometry(product_copy,doc_file,old_id) 
    463             generate_ArbreFile(product_copy,doc_file) 
    464                      
     669            Product_to_ArbreFile(product_copy,doc_file) 
     670            doc_file.document.no_index=False # to reverse no_index=True make in document3D.views.generate_part_doc_links 
     671            doc_file.document.save()       
    465672            ctrl=get_controller(doc_file.document.type) 
    466673            ctrl=ctrl(doc_file.document,user) 
     
    469676     
    470677def is_decomposable(doc3d): 
     678    """ 
     679    :param doc3d: :class:`.document3D` 
     680     
     681    One :class:`.document3D` is decomposable if it contains a :class:`.DocumentFile` whit a :class:`~django.core.files.File` **.stp** attached and this file contains assemblys, 
     682    in addition, the :class:`.DocumentFile` must respect the property checkout_valid and should be unlocked 
     683     
     684    """ 
    471685    if not ArbreFile.objects.filter(stp__document=doc3d,  
    472686            stp__deprecated=False, stp__locked=False, 
     
    487701 
    488702def update_geometry(product,doc_file,old_doc_id): 
    489  
    490      
    491     
    492     if not product.geometry==None: 
     703    """ 
     704    :param product: :class:`.Product` that represents a sub-arborescense of the file step that was decompose 
     705    :type plmobject: :class:`.Product` 
     706    :param doc_file: :class:`.DocumentFile` that will be updated 
     707    :param doc_file: Identifies the :class:`.DocumentFile` root of the decomposition 
     708 
     709     
     710    Copy the content of :class:`.GeometryFile` determined by his index(**product**.geometry) belonging to the :class:`.DocumentFile` identified by **old_doc_id**  
     711    generating a new entity :class:`.GeometryFile` connected to the :class:`.DocumentFile` (**doc_file**) 
     712        
     713    """    
     714    if not product.geometry==False: 
    493715 
    494716        old_GeometryFile=GeometryFile.objects.get(stp__id=old_doc_id,index=product.geometry) 
     
    514736 
    515737 
    516  
     738def ArbreFile_to_Product(doc_file,recursif=None): 
     739 
     740    """ 
     741    :param product: If recursif is True we explore the bom-child of the decomposition to compose the :class:`.Product` (**product**) 
     742    :param doc_file: :class:`.DocumentFile` for which the Product will be generated 
     743     
     744    For a :class:`.DocumentFile` and the :class:`.ArbreFile` related to him, it recovers the :class:`~django.core.files.File` .arb, and  constructs the :class:`.Product` that represent the arborescense. 
     745     
     746    If the file was decomposed and **recursif** is true, completes the :class:`.Product` with relation to the bom-child of the decomposition 
     747     
     748    """ 
     749 
     750    try: 
     751        new_ArbreFile=ArbreFile.objects.get(stp=doc_file) 
     752    except: 
     753        return False 
     754 
     755 
     756    product =Product_from_Arb(json.loads(new_ArbreFile.file.read())) 
     757    if recursif and product: 
     758        child_ArbreFile_to_Product(doc_file,product,product_root=product,deep=1)         
     759             
     760    return product 
     761     
     762 
     763         
     764         
     765         
     766def add_child_GeometryFiles(product,files_to_add): 
     767    """ 
     768    :param product: :class:`.Product` that represents a arborescense 
     769    :param files_to_add: list where add the :class:`.GeometryFiles` childs founded 
     770     
     771    We explore the :class:`.Product` (**product**) looking for :class:`.GeometryFiles` of his childs 
     772      
     773    """ 
     774    for link in product.links: 
     775        if not link.product.doc_id==product.doc_id and link.product.visited==False: 
     776 
     777            link.product.visited=True 
     778            files_to_add+=list(GeometryFile.objects.filter(stp__id=link.product.doc_id)) 
     779            add_child_GeometryFiles(link.product,files_to_add) 
     780                        
     781                             
     782                             
     783def child_ArbreFile_to_Product(doc_file,product,product_root,deep): 
     784    """ 
     785    :param product: :class:`.Product` to expanding  
     786    :param doc_file: :class:`.DocumentFile` related to **product** 
     787    :param product_root: :class:`.Product` root , **product** is a sub-branch of **product_root** 
     788    :deep: Depth of **product** in the arborescense 
     789     
     790     
     791    For a :class:`.DocumentFile` (**doc_file**) and his :class:`.Product` (**product**) related , it explore the Bom-Child looking for :class:`.Product` of his childrens and adds it to the **product** 
     792      
     793    """ 
     794     
     795    stp_related,list_loc=get_step_related(doc_file) 
     796 
     797    for i,stp in enumerate(stp_related):     
     798 
     799         
     800        new_ArbreFile=ArbreFile.objects.get(stp=stp) 
     801        new_product=Product_from_Arb(json.loads(new_ArbreFile.file.read()),product=False,product_root=product_root,deep=deep,to_update_product_root=product)   
     802 
     803                                                                                  
     804        for location in list_loc[i]: 
     805            product.links[-1].add_occurrence(location.name,location) 
     806             
     807        if new_product: 
     808            child_ArbreFile_to_Product(stp,new_product,product_root,deep+1)                        
     809 
     810 
     811                              
     812 
     813def get_step_related(doc_file): 
     814    """ 
     815 
     816    :param doc_file: :class:`.DocumentFile` of which we want to know the :class:`.DocumentFile` in which it was decomposed and his relatives :class:`.Location_link`     
     817     
     818    For a certain :class:`.DocumentFile` (**doc_file**), if has been decomposed across a :class:`.Part` (attribute PartDecompose of :class:`.Document3D` (**doc_file.document** ) 
     819    we recover all the :class:`.ParentChildLink` of the :class:`.Part` and we look for each of them for  possibles  :class:`.Location_link`, these :class:`.Location_link` indicate that the :class:`.ParentChildLink` was the result of a descomposition.If this is the case ,  we are going to look for the  :class:`.DocumentFile` present in :class:`.Document3D` whose attribute PartDecompose is the **child** of the :class:`.ParentChildLink`. 
     820       
     821    We return all  :class:`.DocumentFile` that fulfill these condition together with the list of :class:`.Location_link` relatives of each :class:`.DocumentFile` 
     822     
     823 
     824    """ 
     825    stp_related=[] 
     826    list_loc=[] 
     827    Doc3D=Document3D.objects.get(id=doc_file.document.id) 
     828    part=Doc3D.PartDecompose 
     829     
     830    if part: 
     831        list_link=ParentChildLink.objects.filter(parent=part, end_time=None) 
     832        for i in range(len(list_link)): 
     833            locations=list(Location_link.objects.filter(link=list_link[i])) 
     834            if locations:  
     835                 
     836                Doc3D=Document3D.objects.filter(PartDecompose=list_link[i].child) 
     837                if Doc3D.exists(): 
     838                    STP_file=Doc3D[0].files.filter(is_stp) 
     839                    if STP_file.exists(): 
     840                        stp_related.append(STP_file[0]) 
     841                        list_loc.append(locations) 
     842                    else: 
     843                        raise Document3D_link_Error 
     844 
     845    else: 
     846        pass 
     847    return stp_related , list_loc 
     848                             
     849                                                        
     850 
     851     
     852     
     853 
     854         
     855def Product_to_ArbreFile(product,doc_file): 
     856    """ 
     857     
     858    :param product: :class:`.Product` that contains the information about the arborescense to generate a new :class:`~django.core.files.File` **.arb** 
     859    :param doc_file: :class:`.DocumentFile` related to **product** for which the new :class:`.ArbreFile` is going to be generated 
     860     
     861    Generates a new :class:`.ArbreFile` associated with a :class:`.DocumentFile` from a :class:`.Product` 
     862     
     863    Departing from the information contained in the :class:`.Product` it is going to generate a :class:`~django.core.files.File` **.arb** for the new :class:`.ArbreFile` 
     864      
     865    """    
     866    data=data_for_product(product) 
     867 
     868    fileName, fileExtension = os.path.splitext(doc_file.filename)  
     869    new_ArbreFile= ArbreFile(decomposable=product.is_decomposable) 
     870    new_ArbreFile.stp = doc_file 
     871    name = new_ArbreFile.file.storage.get_available_name(fileName+".arb") 
     872    path = os.path.join(new_ArbreFile.file.storage.location, name) 
     873    new_ArbreFile.file = name 
     874    new_ArbreFile.save() 
     875    directory = os.path.dirname(path.encode())         
     876    if not os.path.exists(directory): 
     877        os.makedirs(directory) 
     878    output = open(path.encode(),"w") 
     879    output.write(json.dumps(data))         
     880    output.close()  
     881    return new_ArbreFile.file.path    
    517882     
    518883 
  • trunk/openPLM/document3D/tests/arborescense.py

    r1005 r1022  
    11from openPLM.plmapp.tests.views import CommonViewTest 
    2 from openPLM.document3D.models import  Document3DController  
    3 from django.core.files import File 
    4 from openPLM.document3D.arborescense import read_ArbreFile 
     2from openPLM.document3D.models import  Document3DController ,ArbreFile_to_Product 
     3from django.core.files import File  
    54class arborescense_Test(CommonViewTest): 
    65 
     
    2221                       
    2322"""                        
    24     def test_read_ArbreFile(self): 
     23    def test_ArbreFile_to_Product(self): 
    2524         
    2625        #We verify if the structure of the tree is the same for a file without decompose  and the new file generated once decomposed 
    2726         
    28         product=read_ArbreFile(self.stp) 
     27        product=ArbreFile_to_Product(self.stp) 
    2928        reponse=self.post(self.base_url+"decompose/"+str(self.stp.id)+"/",self.data_to_decompose) 
    3029        doc_file=self.document.files[0]  
    31         product2=read_ArbreFile(doc_file,self.user)   
     30        product2=ArbreFile_to_Product(doc_file,self.user)   
    3231        self.assertTrue(same_estructure(product,product2)) 
    3332     
  • trunk/openPLM/document3D/tests/decomposer.py

    r974 r1022  
    11from openPLM.plmapp.tests.views import CommonViewTest 
    2 from openPLM.document3D.models import  Document3DController , ArbreFile ,GeometryFile , is_decomposable 
     2from openPLM.document3D.models import  Document3DController , ArbreFile ,GeometryFile , is_decomposable , ArbreFile_to_Product 
    33from openPLM.plmapp.models import  DocumentFile 
    44from django.core.files import File 
    5 from openPLM.document3D.arborescense import read_ArbreFile 
     5 
    66#from openPLM.document3D.decomposer import decomposer_all  , is_decomposable  #decomposer_product #diviser 
    77from openPLM.document3D.STP_converter_WebGL import NEW_STEP_Import ,GetLabelNom 
     
    2323        self.list_document_controller.append(Document3DController.create('doc3', 'Document3D', 
    2424                'a', self.user, self.DATA))                                        
    25         self.links=read_ArbreFile(self.stp).links 
     25        self.links=ArbreFile_to_Product(self.stp).links 
    2626        self.my_step_importer=NEW_STEP_Import(self.stp.file.path,self.stp.id) 
    2727        self.product=self.my_step_importer.generate_product_arbre()  
     
    4545        new_stp=self.document.files[0] 
    4646        self.assertEqual(len(to_index),3) 
    47         self.assertEqual(read_ArbreFile(new_stp).links,[]) 
     47        self.assertEqual(ArbreFile_to_Product(new_stp).links,[]) 
    4848 
    4949        self.assertEqual(len(DocumentFile.objects.all()),4)         
     
    104104         
    105105 
    106         product=read_ArbreFile(doc_file)        
     106        product=ArbreFile_to_Product(doc_file)        
    107107          
    108108        self.assertEqual(self.product.name,product.name) 
  • trunk/openPLM/document3D/tests/views.py

    r1005 r1022  
    66""" 
    77#openPLM3D="enabled" ./manage.py test document3D --settings=settings_tests 
     8#/var/django/openPLM/trunk/docs$ make html 
     9#firefox _build/html/index.html 
     10#/var/django/openPLM/trunk/docs/devel/applications/document3D 
    811from django.http import HttpResponse ,HttpResponseRedirect , HttpRequest 
    912from django.test import TestCase 
    1013from openPLM.document3D.views import * 
     14from openPLM.document3D.models import * 
    1115from openPLM.document3D.forms import * 
    1216from openPLM.plmapp.tests.views import CommonViewTest 
    13 from openPLM.document3D.models import  Document3DController , Document_part_doc_links_Error 
     17from openPLM.document3D.models import  Document3DController , Document_Generate_Bom_Error 
    1418from django.core.files import File 
    1519 
     
    2226        self.document = Document3DController.create('doc1', 'Document3D', 
    2327                'a', self.user, self.DATA) 
    24                  
     28               
    2529    def update_time(self,data): 
    2630        data.update({u'last_modif_time': [u'%s-%s-%s %s:%s:%s'%(self.document.mtime.year,self.document.mtime.month,self.document.mtime.day,self.document.mtime.hour,self.document.mtime.minute,self.document.mtime.second)], 
    2731           u'last_modif_microseconds' : [u'%s'%self.document.mtime.microsecond] 
    2832           }) 
    29     """                    
     33            
     34    def update_data(self,data,new_doc_file,update_time=True): 
     35        product=ArbreFile_to_Product(new_doc_file) 
     36        index=[1] 
     37        lifecycle='draft_official_deprecated' 
     38        part_type='Part' 
     39        decomposition_fromPOST_data(data,product,index,self.group.id,lifecycle,part_type) 
     40        if update_time: 
     41            self.update_time(data) 
     42    """                        
    3043    def test_view3D_stp_decompose(self): 
    31         f=open("document3D/data_test/test.stp") 
     44        f=open("document3D/data_test/test2.stp") 
    3245        myfile = File(f) 
    3346        new_doc_file=self.document.add_file(myfile)  
    34         self.controller.attach_to_document(self.document.object)                                                                    
    35         data = data1 
    36         self.update_time(data) 
    37         self.post(self.base_url+"decompose/"+str(new_doc_file.id)+"/",data)  
    38         response = self.get(self.document.object.plmobject_url+"3D/")         
    39         self.assertEqual(len(response.context["GeometryFiles"]), 3) 
    40     """          
     47        self.controller.attach_to_document(self.document.object)         
     48        data={}    
     49        self.update_data(data,new_doc_file) 
     50        self.post(self.base_url+"decompose/"+str(new_doc_file.id)+"/",data) 
     51        self.assertFalse(is_decomposable(self.document.object)) 
     52        reponse = self.get(self.document.object.plmobject_url+"3D/")         
     53        self.assertEqual(len(reponse.context["GeometryFiles"]), 5) 
     54                        
     55 
     56             
    4157    def test_3D_no_stp_associe(self):    
    4258     
     
    4460        self.assertEqual(response.context["GeometryFiles"], []) 
    4561        self.assertEqual(response.context["javascript_arborescense"], False) 
    46          
     62              
    4763    def test_3D_stp_associe_sans_arborescense(self):    
    4864        f=open("document3D/data_test/test.stp") 
     
    7187        self.assertNotEqual(response.context["javascript_arborescense"], False)   
    7288        
    73 class Document3DBomViewTestCase(CommonViewTest): 
    74     def setUp(self): 
    75         super(Document3DBomViewTestCase, self).setUp() 
    76         self.document = Document3DController.create('doc1', 'Document3D', 
    77                 'a', self.user, self.DATA) 
     89 
    7890 
    7991    def test_bom_child(self): 
     
    123135        response = self.get(self.base_url+"decompose/"+str(new_doc_file.id)+"/")   
    124136                         
    125 class view_decomposeTest(CommonViewTest): 
    126  
    127     def setUp(self): 
    128         super(view_decomposeTest, self).setUp() 
    129         self.document = Document3DController.create('doc1', 'Document3D', 
    130                 'a', self.user, self.DATA) 
    131  
    132  
    133     def update_time(self,data): 
    134         data.update({u'last_modif_time': [u'%s-%s-%s %s:%s:%s'%(self.document.mtime.year,self.document.mtime.month,self.document.mtime.day,self.document.mtime.hour,self.document.mtime.minute,self.document.mtime.second)], 
    135            u'last_modif_microseconds' : [u'%s'%self.document.mtime.microsecond] 
    136            }) 
    137137                   
    138138    #verificar los links creados en las buenas coordenadas       
     
    144144        response = self.get(self.base_url+"decompose/"+str(new_doc_file.id)+"/") 
    145145        # TODO: check forms 
    146 """  
     146 
     147 
    147148    def test_display_decompose_form_post(self): 
    148149        f=open("document3D/data_test/test.stp") 
    149150        myfile = File(f) 
    150151        new_doc_file=self.document.add_file(myfile)      
     152        self.controller.attach_to_document(self.document.object)     
     153                                                               
     154        data={} 
     155        self.update_data(data,new_doc_file) 
     156 
     157 
     158        reponse_post = self.post(self.base_url+"decompose/"+str(new_doc_file.id)+"/",data) 
     159        self.assertRedirects(reponse_post, self.base_url + "BOM-child/") 
     160 
     161            
     162    def test_display_decompose_time_modification_diferent(self): 
     163        f=open("document3D/data_test/test.stp") 
     164        myfile = File(f) 
     165        new_doc_file=self.document.add_file(myfile)      
    151166        self.controller.attach_to_document(self.document.object)                                                           
    152         data = data1 
    153         self.update_time(data) 
    154         reponse_post = self.post(self.base_url+"decompose/"+str(new_doc_file.id)+"/",data) 
    155         self.assertRedirects(reponse_post, self.base_url + "BOM-child/") 
    156 """ 
    157 """         
    158     def test_display_decompose_time_modification_diferent(self): 
    159         f=open("document3D/data_test/test.stp") 
    160         myfile = File(f) 
    161         new_doc_file=self.document.add_file(myfile)      
    162         self.controller.attach_to_document(self.document.object)                                                           
    163         data = data1 
     167        data={} 
     168        self.update_data(data,new_doc_file) 
     169         
     170        data.update({u'last_modif_time': [u'%s-%s-%s %s:%s:%s'%             (self.document.mtime.year,(self.document.mtime.month),self.document.mtime.day,self.document.mtime.hour-1,self.document.mtime.minute-2,self.document.mtime.second)], 
     171           u'last_modif_microseconds' : [u'%s'%self.document.mtime.microsecond] 
     172           }) 
    164173        reponse_post = self.post(self.base_url+"decompose/"+str(new_doc_file.id)+"/",data) 
    165174        self.assertEqual(reponse_post.context["extra_errors"],"The Document3D associated with the file STEP to decompose has been modified by another user while the forms were refilled:Please restart the process") 
    166 """ 
    167 """         
     175 
     176              
    168177    def test_display_decompose_time_modification_invalid(self): 
    169178        f=open("document3D/data_test/test.stp") 
     
    177186        reponse_post = self.post(self.base_url+"decompose/"+str(new_doc_file.id)+"/",data) 
    178187        self.assertEqual(reponse_post.context["extra_errors"],"Mistake reading of the last modification of the document, please restart the task") 
    179 """         
    180 """                         
     188        
     189                  
    181190    def test_display_decompose_file_locked(self): 
    182191        f=open("document3D/data_test/test.stp") 
     
    189198        reponse_post = self.post(self.base_url+"decompose/"+str(new_doc_file.id)+"/",data) 
    190199        self.assertEqual(reponse_post.context["extra_errors"],"The Document3D associated with the file STEP to decompose has been modified by another user while the forms were refilled:Please restart the process") 
    191 """         
    192 """     
     200 
    193201    def test_display_decompose_Document_part_doc_links_Error(self): 
    194202        f=open("document3D/data_test/test.stp") 
     
    200208        reponse=self.post(self.base_url+"decompose/"+str(new_doc_file.id)+"/",data) 
    201209        self.assertEqual(reponse.context["extra_errors"],u"Columns reference, type, revision are not unique") 
    202 """    
    203 """      
     210 
    204211    def test_display_decompose_Document3D_decomposer_Error(self): 
    205212        f=open("document3D/data_test/test.stp") 
     
    212219        reponse=self.post(self.base_url+"decompose/"+str(new_doc_file.id)+"/",data) 
    213220        self.assertEqual(reponse.context["extra_errors"],u"Error while the file step was decomposed")         
    214 """ 
    215 """          
     221         
    216222    def test_display_decompose_bom_formset_error_post(self): 
    217223        f=open("document3D/data_test/test.stp") 
     
    224230        self.assertEqual(reponse_post.context["bom_formset"].errors,[{'quantity': [u'This field is required.']}, {}]) 
    225231 
    226 """ 
    227 """ 
     232 
    228233    def test_display_decompose_part_type_formset_error_post(self): 
    229234        f=open("document3D/data_test/test.stp") 
     
    237242                [{'type_part': [u'Select a valid choice. Part54545 is not one of the available choices.']}, {}] 
    238243) 
    239 """ 
    240 """      
     244    
    241245    def test_display_decompose_creation_formset_error_post(self): 
    242246        f=open("document3D/data_test/test.stp") 
     
    253257                self.assertEqual(atributes[0].errors,{'group': [u'Bad group, check that the group exists and that you belong to this group.']}) 
    254258            index+=1 
    255 """     
     259 
     260    """    
    256261                           
    257262 
     
    465470  u'form-1-type_document3D': [u'not_exits_Document4D362182'], 
    466471  u'1-reference': [u'DOC_00002']} 
    467   
     472   
     473   
     474def decomposition_fromPOST_data(data,product,index,group,lifecycle,part_type): 
     475 
     476    if product.links: 
     477        for order , link in enumerate(product.links): 
     478            data.update({ 
     479                    "%s-order"%index[0] : [u'%s'%((order+1)*10)], 
     480                    "%s-quantity"%index[0] : [u'%s'%link.quantity], 
     481                    "%s-unit"%index[0] : [u'-'], 
     482            })             
     483            if not link.product.visited:  
     484                data.update({ 
     485                "%s-type_part"%index[0] : [u'%s'%part_type], 
     486                "%s-part-reference"%index[0] : [u'%s'%index[0]], 
     487                "%s-part-revision"%index[0] : [u'%s'%index[0]], 
     488                "%s-part-name"%index[0]     :  [u'%s'%index[0]],   
     489                "%s-part-lifecycle"%index[0] : [u'%s'%lifecycle] ,  
     490                "%s-part-group"%index[0] : [u'%s'%group] ,   
     491                "%s-document-reference"%index[0] : [u'%s'%index[0]], 
     492                "%s-document-revision"%index[0] : [u'%s'%index[0]], 
     493                "%s-document-name"%index[0]     :  [u'%s'%index[0]],   
     494                "%s-document-lifecycle"%index[0] : [u'%s'%lifecycle] , 
     495                "%s-document-group"%index[0] :[u'%s'%group] ,     
     496                }) 
     497                link.product.visited=True          
     498                index[0]+=1                  
     499                decomposition_fromPOST_data(data,link.product,index,group,lifecycle,part_type)                  
     500            else: 
     501                index[0]+=1  
     502 
     503                    
     504 
     505 
     506         
  • trunk/openPLM/document3D/views.py

    r1013 r1022  
    2020@handle_errors 
    2121def display_3d(request, obj_ref, obj_revi): 
    22     """ Manage html page for 3D 
    23  
    24     Manage html page which displays the 3d files STEP of the selected object. 
    25     It computes a context dictionnary based on 
    26  
    27     .. include:: views_params.txt 
     22    """ 
     23 
     24    Manage html page which displays the 3d view of the :class:`.DocumentFile` STEP attached to a :class:`.Document3D`. 
     25 
     26    For the correct visualization there is necessary to extract all the geometries contained in the :class:`~django.core.files.File` **.geo** present in the :class:`.GeometryFile` relative to :class:`.DocumentFile` that we want to show and also the **.geo** contained in to the :class:`.DocumentFile` in which the DocumentFile to show has been decomposed. 
     27     
     28    We need to generate also the code javascript to manage these geometries. 
     29    To generate this code we need the information about the arborescense of the :class:`.DocumentFile` , this arborescense is obtained of the :class:`~django.core.files.File` **.arb** corresponding to the :class:`.ArbreFile` connected to the :class:`.DocumentFile`.The information the file **.arb** turns into a :class:`.Product` that we use to call  the function :meth:`.generate_javascript_for_3D` that return the code required 
     30 
    2831    """ 
    2932 
     
    4144        javascript_arborescense=False 
    4245    else: 
    43         #puede haberlos repetidos, arreglar 
     46 
     47        product=ArbreFile_to_Product(doc_file,recursif=True) 
    4448        GeometryFiles=list(GeometryFile.objects.filter(stp=doc_file)) 
    45         add_child_GeometryFiles(doc_file,GeometryFiles) 
    46         product=read_ArbreFile(doc_file,True) 
     49        if product:   
     50            add_child_GeometryFiles(product,GeometryFiles) 
     51 
     52         
    4753        javascript_arborescense=generate_javascript_for_3D(product) 
    4854 
     
    116122def display_decompose(request, obj_type, obj_ref, obj_revi, stp_id): 
    117123 
    118     #incluir los script para autocompletar nombres y esos ole1 
    119     """ 
    120     Manage html page which displays the chidren of the selected object. 
    121     It computes a context dictionnary based on 
    122  
    123     .. include:: views_params.txt 
     124 
     125    """ 
     126    :param obj_type: Type of the :class:`.Part` from which we want to realize the decomposition 
     127    :param obj_ref: Reference of the :class:`.Part` from which we want to realize the decomposition 
     128    :param obj_revi: Revision of the :class:`.Part` from which we want to realize the decomposition 
     129    :param stp_id: Id that identify the :class:`.DocumentFile` contained in a :class:`.Document3D` attached to the :class:`.Part` (identified by **obj_type**, **obj_ref**, **obj_revi**) that we will decompose  
     130     
     131     
     132    When we demand the decomposition across the web form, the following tasks are realized 
     133     
     134    -We check that the :class:`.Document3D` that contains the :class:`.DocumentFile` (**stp_id**) that will be decomposed has not been modified since the generation of the form 
     135     
     136    -We check the validity of the information got in the form 
     137     
     138    -If exists a :class:`.DocumentFile` native file related to :class:`.DocumentFile` (**stp_id**) that will be decomposed 
     139     
     140        -then this one was depreciated (afterwards will be promoted) 
     141         
     142    -The :class:`.DocumentFile` (**stp_id**) was locked (afterwards will be promoted) 
     143     
     144    -We set the :class:`.Part` (**obj_type**, **obj_ref**, **obj_revi**) like the attribute PartDecompose of the :class:`.Document3D` that contains the :class:`.DocumentFile` (**stp_id**) 
     145     
     146    -We call the function :meth:`.generate_part_doc_links_AUX` (with the property transaction.commit_on_success) 
     147            
     148        -We generate the arborescense (:class:`.product`) of the :class:`.DocumentFile` (**stp_id**)) 
     149         
     150        -The bomb-child of Parts (in relation to the arborescense of the :class:`.DocumentFile` (**stp_id**)) has been generated 
     151         
     152        -For every :class:`.ParentChildLink` generated in the previous condition  we attach all the :class:`.Location_link` relatives 
     153         
     154        -To every generated :class:`.Part` a :class:`.Document3D` has been attached and this document as been set like the attribute PartDecompose of the :class:`.Part` 
     155          
     156        -The attribute doc_id of every node of the arborescense (:class:`.Product`) is now the relative id of :class:`.Document3D` generated in the previous condition 
     157         
     158        -To every generated :class:`.Document3D` has been added a new empty(locked) :class:`.DocumentFile` STP 
     159         
     160        -The attribute doc_path of every node of the arborescense(:class:`.Product`) is now the path of :class:`.DocumentFile` STP generated in the previous condition 
     161         
     162    -We update the indexes for the objects generated 
     163     
     164    -We call the processus decomposer_all(with celeryd)          
     165             
     166     
     167 
    124168    """ 
    125169 
     
    130174    if not stp_file.document_id in doc_linked_to_part: 
    131175        raise ValueError("Not allowed operation.The Document and the Part are not linked") 
    132     if Document3D.objects.filter(PartDecompose=obj.object): 
     176    if Document3D.objects.filter(PartDecompose=obj.object).exists(): 
    133177        raise ValueError("Not allowed operation.This Part already forms a part of another decomposition") 
    134178    try: 
     
    137181        raise ValueError("Not allowed operation.The document is not a subtype of document3D") 
    138182 
    139     if doc3D.PartDecompose:# y si el documento no es 3D 
     183    if doc3D.PartDecompose: 
    140184        raise ValueError("Not allowed operation.This Document already forms a part of another decomposition") 
     185         
     186 
    141187 
    142188    if request.method == 'POST': 
     189     
     190 
    143191        extra_errors="" 
    144         product=read_ArbreFile(stp_file) 
    145         #part_type_formset = Select_Doc_Part_types(request.POST) 
    146         #bom_formset = Select_Order_Quantity_types(request.POST) 
     192        product=ArbreFile_to_Product(stp_file) 
    147193        last_time_modification=Form_save_time_last_modification(request.POST) 
    148         #comprobar que la parte no ha sido descompuesta con anterioridad 
    149194        obj.block_mails() 
    150195 
     
    157202            index=[1] 
    158203            if clear_form(request,assemblys,product,index,obj_type): 
    159                 # y si tiene un nativo   que hago con el 
     204 
    160205                if (same_time(old_modification_data_time,  
    161206                              old_modification_data_microsecond, 
    162207                              document_controller.mtime) 
    163                     and product and stp_file.checkout_valid and not stp_file.locked): 
     208                    and stp_file.checkout_valid and not stp_file.locked): 
    164209                     
    165210 
    166                      
     211 
    167212                    
    168213                    stp_file.locked=True 
    169214                    stp_file.locker=User.objects.get(username=settings.COMPANY) 
    170215                    stp_file.save(False) 
    171                     native_related=stp_file.native_related 
    172                         
     216 
     217                    doc3D.PartDecompose=obj.object 
     218                    doc3D.save() 
     219                     
     220                    native_related=stp_file.native_related                        
    173221                    if native_related: 
    174222                        native_related.deprecated=True 
     
    184232                        update_indexes.delay(instances)  
    185233                    except Exception as excep: 
    186                         if type(excep) == Document_part_doc_links_Error: 
     234                        if type(excep) == Document_Generate_Bom_Error: 
    187235                            delete_files(excep.to_delete) 
    188236 
    189237                         
    190                          
     238 
    191239                        extra_errors = unicode(excep) 
    192240                        stp_file.locked = False 
    193241                        stp_file.locker = None 
    194242                        stp_file.save(False) 
     243                        doc3D.PartDecompose=None 
     244                        doc3D.save() 
    195245                        if native_related: 
    196246                            native_related.deprecated=False 
    197247                            native_related.save(False) 
    198248                    else: 
    199                          
     249             
    200250                        decomposer_all.delay(stp_file.pk,json.dumps(data_for_product(product)),obj.object.pk,native_related_pk,obj._user.pk) 
    201                         #decomposer_all(stp_file.pk,json.dumps(data_for_product(product)),obj.object.pk,native_related_pk,obj._user.pk) 
     251 
    202252                        return HttpResponseRedirect(obj.plmobject_url+"BOM-child/") 
    203253   
     
    207257 
    208258                else: 
     259 
    209260                    extra_errors="The Document3D associated with the file STEP to decompose has been modified by another user while the forms were refilled:Please restart the process" 
    210261                 
     
    214265 
    215266        else: 
     267 
    216268            extra_errors="Mistake reading of the last modification of the document, please restart the task" 
    217269 
     
    223275 
    224276        last_time_modification.fields["last_modif_microseconds"].initial=document_controller.mtime.microsecond 
    225         product=read_ArbreFile(stp_file) 
     277        product=ArbreFile_to_Product(stp_file) 
    226278        if not product or not product.links: 
    227279            return HttpResponseRedirect(obj.plmobject_url+"BOM-child/") 
     
    229281        group = obj.group 
    230282        index=[1,0] # index[1] to evade generate holes in part_revision_default generation 
    231         initialiser_assemblys(assemblys,product,group,request,index,obj_type) 
     283        initialiser_assemblys(assemblys,product,group,request.user,index,obj_type) 
    232284         
    233285 
     
    235287         
    236288 
    237     deep_assemblys=sort_assemblys(assemblys) 
     289    deep_assemblys=sort_assemblys_by_depth(assemblys) 
    238290    ctx.update({'current_page':'decomposer',  # aqui cambiar 
    239291                'deep_assemblys' : deep_assemblys, 
     
    246298     
    247299     
    248 def sort_assemblys(assemblys): 
     300def sort_assemblys_by_depth(assemblys): 
    249301 
    250302    new_assembly=[] 
    251303    for elem in assemblys: 
    252         print elem[3] 
    253304        for i in range(elem[3]+1-len(new_assembly)): 
    254305            new_assembly.append([])         
     
    261312def clear_form(request,assemblys, product,index,obj_type): 
    262313 
     314    """ 
     315     
     316    :param assemblys: will be refill whit the information necessary the generate the forms 
     317    :param product: :class:`.Product` that represents the arborescense of the :class:`~django.core.files.File` .stp contained in a :class:`.DocumentFile` 
     318    :param index: Use  to mark and to identify the **product** s that already have been visited 
     319    :param obj_type: Type of the :class:`.Part` from which we want to realize the decomposition  
     320     
     321    It checks the validity of the forms contained in **request** 
     322     
     323     
     324     
     325    If the forms are not valide, he returns the information to refill the new forms contained in **assemblys**. 
     326      
     327    Refill **assemblys** with the different assemblys of the file step , we use **index** to mark and to identify the **product** s that already have been visited 
     328         
     329    For every Assembly we have the next information: 
     330     
     331        -Name of assembly 
     332          
     333        -Visited , If assembly is sub-assembly of more than an assembly, this attribute will be **False** for all less one of the occurrences 
     334         
     335            If visited is **False**, we will be able to modify only the attributes **Order** , **Quantity** and **Unit** refered to the :class:`.ParentChildLink` in the form 
     336             
     337            If visited is not **False** , it will be a new id acording to **index** (>=1) generated to identify the assembly 
     338             
     339        -Depth  of assembly 
     340          
     341        -**obj_type** , type of :class:`.Part` of Assembly 
     342         
     343        -A list with the products that compose the assembly 
     344         
     345            for each element in the list: 
     346             
     347                -part_type contains the form to select the type of :class:`.Part`   
     348                 
     349                -ord_quantity contains the forms to select Order , Quantity and Unit refered to the :class:`.ParentChildLink` 
     350                 
     351                -creation_formset contains the form for the creation of the part selected in part_type and of one :class:`.Document3D` 
     352                 
     353                -name_child_assemblys contains the name of the element 
     354                 
     355                -is_assembly determine if the element is a single product or another assembly  
     356                 
     357                -prefix contains the **index** of the assembly  if he is visited for first time , else is False 
     358                 
     359                -ref contains the **index** of the assembly if he was visited previously, else False  
     360                    
     361    """ 
    263362 
    264363    creation_formset=[] 
    265364    initial_bom_values=[] 
    266365    initial_deep_values=[] 
    267     child_assemblys=[] 
     366    name_child_assemblys=[] 
    268367    is_assembly=[] 
    269368    part_type=[] 
     
    275374        for link in product.links: 
    276375         
    277  
     376             
    278377            ord_qty=Order_Quantity_Form(request.POST,prefix=index[0]) 
    279             link.visited=index[0] # para evitar en caso de nodos repetidos utilizar el link del padre 
     378            link.visited=index[0] 
    280379 
    281380 
     
    285384            ord_quantity.append(ord_qty) 
    286385            is_assembly.append(link.product.is_assembly) 
    287             child_assemblys.append(link.product.name) 
     386            name_child_assemblys.append(link.product.name) 
    288387                         
    289388            if not link.product.visited: 
     389                link.product.visited=index[0] 
     390                   
    290391                part_ctype=Doc_Part_type_Form(request.POST,prefix=index[0]) 
    291392                if not part_ctype.is_valid(): 
     
    301402                    valid=False 
    302403                if not doc_form.is_valid(): 
     404                    print "4" 
    303405                    valid=False                
    304406 
     
    307409                ref.append(None)           
    308410                part_type.append(part_ctype)  
    309                 link.product.visited=index[0]                  
     411                                
    310412                index[0]+=1             
    311413 
     
    322424         
    323425                                 
    324         assemblys.append((zip(part_type ,ord_quantity,  creation_formset,  child_assemblys , is_assembly , prefix , ref )  , product.name , product.visited , product.deep, obj_type))             
     426        assemblys.append((zip(part_type ,ord_quantity,  creation_formset,  name_child_assemblys , is_assembly , prefix , ref )  , product.name , product.visited , product.deep, obj_type))             
    325427    return valid                                     
    326428         
    327429         
    328430    
    329 def initialiser_assemblys(assemblys,product,group,request,index, obj_type): 
    330  
     431def initialiser_assemblys(assemblys,product,group,user,index, obj_type): 
     432    """ 
     433     
     434    :param assemblys: will be refill whit the information necessary the generate the forms 
     435    :param product: :class:`.Product` that represents the arborescense of the :class:`~django.core.files.File` .stp contained in a :class:`.DocumentFile` 
     436    :param index: Use  to mark and to identify the **product** s that already have been visited 
     437    :param obj_type: Type of the :class:`.Part` from which we want to realize the decomposition  
     438    :param group: group by default from which we want to realize the decomposition  
     439     
     440             
     441    Returns in assemblys a list initialized with the different assemblies of the file step 
     442         
     443         
     444         
     445    For every Assembly we have the next information: 
     446     
     447        -Name of assembly 
     448          
     449        -Visited , If assembly is sub-assembly of more than an assembly, this attribute will be **False** for all less one of the occurrences 
     450         
     451            If visited is **False**, we will be able to modify only the attributes **Order** , **Quantity** and **Unit** refered to the :class:`.ParentChildLinkin` in the form 
     452             
     453            If visited is not **False** , it will be a new id acording to **index** (>=1) generated to identify the assembly 
     454             
     455        -Depth  of assembly 
     456          
     457        -**obj_type** , type of :class:`.Part` of Assembly 
     458         
     459        -A list with the products that compose the assembly 
     460         
     461            for each element in the list: 
     462             
     463                -part_type contains the form to select the type of :class:`.Part`   
     464                 
     465                -ord_quantity contains the forms to select Order , Quantity and Unit refered to the :class:`.ParentChildLink` 
     466                 
     467                -creation_formset contains the form for the creation of the part selected in part_type and of one :class:`.Document3D` 
     468                 
     469                -name_child_assemblys contains the name of the element 
     470                 
     471                -is_assembly determine if the element is a single product or another assembly  
     472                 
     473                -prefix contains the **index** of the assembly if he is visited for first time , else is False 
     474                 
     475                -ref contains the **index** of the assembly if he was visited previously, else False  
     476 
     477                      
     478    """  
    331479    creation_formset=[] 
    332480    initial_bom_values=[] 
    333481    initial_deep_values=[] 
    334     child_assemblys=[] 
     482    name_child_assemblys=[] 
    335483    is_assembly=[] 
    336484    part_type=[] 
     
    347495            ord_quantity.append(oq) 
    348496            is_assembly.append(link.product.is_assembly) 
    349             child_assemblys.append(link.product.name) 
    350             if not link.product.visited:             
     497            name_child_assemblys.append(link.product.name) 
     498            if not link.product.visited:  
     499                link.product.visited=index[0]            
    351500                part_type.append(Doc_Part_type_Form(prefix=index[0]))  
    352                 part_cform = get_creation_form(request.user, Part, None, (index[1])) # index[0].initial=1 -> -1 
     501                part_cform = get_creation_form(user, Part, None, (index[1])) # index[0].initial=1 -> -1 
    353502                part_cform.prefix = str(index[0])+"-part" 
    354503                part_cform.fields["group"].initial = group 
    355504                part_cform.fields["name"].initial = link.product.name 
    356                 doc_cforms = get_creation_form(request.user, Document3D, None, (index[1])) 
     505                doc_cforms = get_creation_form(user, Document3D, None, (index[1])) 
    357506                doc_cforms.prefix = str(index[0])+"-document" 
    358507                doc_cforms.fields["name"].initial = link.product.name  
     
    360509                prefix.append(index[0]) 
    361510                creation_formset.append([part_cform, doc_cforms])                                 
    362                 link.product.visited=index[0] 
     511 
    363512                ref.append(None) 
    364513                index[0]+=1 
    365514                index[1]+=1                    
    366                 initialiser_assemblys(assemblys,link.product,group,request,index, "Part")                  
     515                initialiser_assemblys(assemblys,link.product,group,user,index, "Part")                  
    367516            else: 
    368517                index[0]+=1  
     
    371520 
    372521 
    373         assemblys.append((zip(part_type ,ord_quantity,  creation_formset,  child_assemblys , is_assembly , prefix , ref )  , product.name , product.visited ,product.deep, obj_type)) 
     522        assemblys.append((zip(part_type ,ord_quantity,  creation_formset,  name_child_assemblys , is_assembly , prefix , ref )  , product.name , product.visited ,product.deep, obj_type)) 
    374523 
    375524@transaction.commit_on_success 
     
    380529def generate_part_doc_links(request,product, parent_ctrl,instances): 
    381530 
    382  
    383  
     531    """ 
     532     
     533 
     534    :param product: :class:`.Product` that represents the arborescense 
     535    :param parent_ctrl: :class:`.Part` from which we want to realize the decomposition 
     536    :param instances: Use to trace the items to update  
     537 
     538         
     539    He reads the forms and generates: 
     540     
     541     
     542    -The bomb-child of Parts (in relation to the **product**)  
     543     
     544    -For every :class:`.ParentChildLink` generated in the condition previous we attach all the :class:`.Location_link` relatives 
     545     
     546    -To every generated :class:`.Part` a :class:`.Document3D` has been attached and Document3D as been set like the attribute PartDecompose of the Part 
     547      
     548    -The attribute doc_id of every node of the arborescense(**product**) is now the relative id of :class:`.Document3D` generated in the previous condition 
     549     
     550    -To every generated :class:`.Document3D` has been added a new empty(locked) :class:`.DocumentFile` STP ( :meth:`.generateGhostDocumentFile` ) 
     551     
     552    -The attribute doc_path of every node of the arborescense(**product**) is now the path of :class:`.DocumentFile` STP generated in the previous condition 
     553    """ 
     554     
    384555    to_delete=[] 
    385556    user = parent_ctrl._user 
    386      
    387     #if product.links:     
     557      
    388558 
    389559    for link in product.links:  
     
    396566            if not link.product.part_to_decompose:  
    397567             
    398  
    399568 
    400569                part_ctype=Doc_Part_type_Form(request.POST,prefix=link.product.visited) 
     
    403572                part_form = get_creation_form(user, cls, request.POST, 
    404573                            prefix=str(link.product.visited)+"-part")  
    405                                
     574                          
    406575                part_ctrl = parent_ctrl.create_from_form(part_form, user, True, True) 
     576 
    407577                instances.append((part_ctrl.object._meta.app_label, 
    408578                    part_ctrl.object._meta.module_name, part_ctrl.object._get_pk_val())) 
    409579 
    410580                c_link = parent_ctrl.add_child(part_ctrl.object,quantity,order,unit) 
     581 
    411582                generate_extra_location_links(link, c_link) 
    412                  
    413583 
    414584                doc_form = get_creation_form(user, Document3D, 
     
    420590                to_delete.append(generateGhostDocumentFile(link.product,doc_ctrl)) 
    421591 
    422                     
     592  
    423593                instances.append((doc_ctrl.object._meta.app_label, 
    424594                    doc_ctrl.object._meta.module_name, doc_ctrl.object._get_pk_val())) 
     
    442612 
    443613        except Exception as excep: 
    444             raise Document_part_doc_links_Error(to_delete,link.product.name)     
     614            #raise excep 
     615            raise Document_Generate_Bom_Error(to_delete,link.product.name)     
    445616     
    446617 
     
    452623     
    453624def generateGhostDocumentFile(product,Doc_controller): 
    454     #importante modifica el arbol 
    455  
     625    """ 
     626    :param product: :class:`.Product` that represents the arborescense 
     627    :param Doc_controller: :class:`.Document3DController` from which we want to generate the :class:`.DocumentFile`  
     628 
     629     
     630    For one :class:`.Product` (**product**) and one :class:`.Document3DController` (**Doc_controller**)generates a :class:`.DocumentFile` with a file .stp emptily without indexation 
     631     
     632    It updates the attributes **doc_id** and **doc_path** of the :class:`.Product` (**product**) in relation of the generated :class:`.DocumentFile` 
     633     
     634    """ 
    456635    doc_file=DocumentFile() 
    457636    name = doc_file.file.storage.get_available_name(product.name+".stp") 
     
    470649            
    471650    doc_file.no_index=True         
    472     doc_file.filename="Ghost" 
     651    doc_file.filename="Ghost.stp" 
    473652    doc_file.size=f.size 
    474653    doc_file.file=name 
     
    479658     
    480659     
    481     ## 
     660 
    482661    product.doc_id=doc_file.id 
    483662 
    484663    product.doc_path=doc_file.file.path  
    485664 
    486     ## 
     665 
    487666    return doc_file.file.path 
    488667 
     
    490669 
    491670 
    492 """ 
    493 def clear_form(request, part_type_formset, bom_formset): 
    494     valid=True 
    495     if bom_formset.is_valid(): 
    496         order_quantity_extra_links=[] 
    497         for form in bom_formset.forms: 
    498             if form.is_valid(): 
    499  
    500                 options=form.cleaned_data 
    501                 order_quantity_extra_links.append([options["order"],options["quantity"],options["unit"]]) 
    502             else: 
    503  
    504                 valid = False 
    505     else: 
    506  
    507         valid=False 
    508  
    509     if part_type_formset.is_valid(): 
    510         index=0 
    511         for form in part_type_formset.forms: 
    512             options=form.cleaned_data 
    513             part = options["type_part"] 
    514             cls = get_all_plmobjects()[part] 
    515             part_form = get_creation_form(request.user, cls, request.POST, 
    516                     prefix=str(index*2)) 
    517             if not part_form.is_valid():#son necesarios? 
    518  
    519                 valid=False 
    520             doc_form = get_creation_form(request.user, Document3D, 
    521                     request.POST, prefix=str(index*2+1)) 
    522             creation_formset.append([part_form,doc_form]) 
    523  
    524             if not doc_form.is_valid(): #son necesarios? 
    525  
    526                 valid=False 
    527             index=index+1 
    528  
    529     else: 
    530  
    531         valid=False 
    532  
    533     if valid: 
    534         return zip(order_quantity_extra_links,creation_formset) 
    535     else: 
    536         return valid 
    537 """ 
    538671@secure_required 
    539672@login_required 
    540673def ajax_part_creation_form(request, prefix): 
    541  
    542  
     674    """ 
     675    It updates the form of an assembly determined by **prefix** without recharging the whole page and respecting the information introduced up to the moment 
     676     
     677    The attributes can change depending on the type of part selected 
     678 
     679    """ 
    543680    tf = Doc_Part_type_Form(request.GET, prefix=prefix) 
    544681 
Note: See TracChangeset for help on using the changeset viewer.