예제 #1
0
 def _gen_U(self, layerNum, objID):
     """For a given layerNum and objID, compute the quantity:
     ```latex
     U_{n,i}(t) = (\cup_{m<n;j} G_{m,j}) \cup (\cup_{k} A_k),
     ```
     where the inner union terms are not included if their intersection
     with B_i is empty.
     """
     layers = self.lithoDict['layers']
     B = layers[layerNum]['objIDs'][objID][
         'B']  # B prism for this layer & objID
     GList = []
     for m in layers.keys():
         if m < layerNum:  # then this is a lower layer
             for j in layers[m].keys():
                 if 'G' not in layers[layerNum]['objIDs'][objID]:
                     self._gen_G(m, j)
                 G = layers[layerNum]['objIDs'][objID]['G']
                 if checkOverlap([B, G]):
                     GList.append(G)
     AList = []
     for A in self.lithoDict['substrate'][()]:
         if checkOverlap([B, A]):
             AList.append(A)
     unionList = GList + AList
     unionObj = genUnion(unionList, consumeInputs=False)
     return unionObj
예제 #2
0
 def exportBuiltParts(self, stepFileDir=None, stlFileDir=None):
     # Now that we are ready to export, we first want to merge all of the
     # 3D renders corresponding to a single shape into one entity:
     totalObjsDict = {}
     for partName in self._buildPartsDict.keys():
         objsList = self._buildPartsDict[partName]
         mergedObj = genUnion(objsList, consumeInputs=True)
         mergedObj.Label = partName
         totalObjsDict[partName] = mergedObj
     # Now that we have merged the objects, we want to center them  in the x-y
     # plane so the distances aren't ridiculous:
     centerObjects(totalObjsDict.values())
     # Finally, we go through the dictionary and export:
     for partName in totalObjsDict.keys():
         obj = totalObjsDict[partName]
         objFCName = obj.Name
         if stepFileDir is not None:
             filePath = stepFileDir + '/' + partName + '.step'
             exportCAD(obj, filePath)
             self.model.registerCadPart(partName,
                                        objFCName,
                                        filePath,
                                        reset=True)
         if stlFileDir is not None:
             filePath = stlFileDir + '/' + partName + '.stl'
             exportMeshed(obj, filePath)
예제 #3
0
 def _gen_G(self, layerNum, objID):
     ''' Generate the gate deposition for a given layerNum and objID.
     '''
     if 'G' not in self.lithoDict['layers'][layerNum]['objIDs'][objID]:
         if () not in self.lithoDict['layers'][layerNum]['objIDs'][objID][
                 'HDict']:
             self.lithoDict['layers'][layerNum]['objIDs'][objID]['HDict'][(
             )] = self._H_offset(layerNum, objID)
         H = genUnion(
             self.lithoDict['layers'][layerNum]['objIDs'][objID]['HDict'][(
             )],
             consumeInputs=False)
         self.trash += [H]
         if self.fillShells:
             G = copy(H)
         else:
             U = self._gen_U(layerNum, objID)
             G = subtract(H, U)
             delete(U)
         self.lithoDict['layers'][layerNum]['objIDs'][objID]['G'] = G
     G = self.lithoDict['layers'][layerNum]['objIDs'][objID]['G']
     partName = self.lithoDict['layers'][layerNum]['objIDs'][objID][
         'partName']
     G.Label = partName
     return G
예제 #4
0
def makeSAG(sketch, zBot, zMid, zTop, tIn, tOut, offset=0.):
    doc = FreeCAD.ActiveDocument
    # First, compute the geometric quantities we will need:
    a = zTop - zMid  # height of the top part
    b = tOut + tIn  # width of one of the trianglular pieces of the top
    alpha = np.abs(np.arctan(a / np.float(b)))  # lower angle of the top part
    c = a + 2 * offset  # height of the top part including the offset
    # horizontal width of the trianglular part of the top after offset
    d = c / np.tan(alpha)
    # horizontal shift in the triangular part of the top after an offset
    f = offset / np.sin(alpha)

    sketchList = splitSketch(sketch)
    returnParts = []
    for tempSketch in sketchList:
        # TODO: right now, if we try to taper the top of the SAG wire to a point, this
        # breaks, since the offset of topSketch is empty. We should detect and handle this.
        # For now, just make sure that the wire has a small flat top.
        botSketch = draftOffset(tempSketch, offset)  # the base of the wire
        midSketch = draftOffset(tempSketch, f + d - tIn)  # the base of the cap
        topSketch = draftOffset(tempSketch, -tIn + f)  # the top of the cap
        delete(tempSketch)  # remove the copied sketch part
        # Make the bottom wire:
        rectPartTemp = extrude(botSketch, zMid - zBot)
        rectPart = copy(rectPartTemp, moveVec=(0., 0., zBot - offset))
        delete(rectPartTemp)
        # make the cap of the wire:
        topSketchTemp = copy(topSketch,
                             moveVec=(0., 0., zTop - zMid + 2 * offset))
        capPartTemp = doc.addObject('Part::Loft', sketch.Name + '_cap')
        capPartTemp.Sections = [midSketch, topSketchTemp]
        capPartTemp.Solid = True
        doc.recompute()
        capPart = copy(capPartTemp, moveVec=(0., 0., zMid - offset))
        delete(capPartTemp)
        delete(topSketchTemp)
        delete(topSketch)
        delete(midSketch)
        delete(botSketch)
        returnParts += [capPart, rectPart]
    returnPart = genUnion(returnParts, consumeInputs=True)
    return returnPart
예제 #5
0
 def _initialize_lithography(self, fillShells=True):
     self.fillShells = fillShells
     # The lithography step requires some infrastructure to track things
     # throughout.
     self.lithoDict = {
     }  # dictionary containing objects for the lithography step
     self.lithoDict['layers'] = {}
     # Dictionary for containing the substrate. () indicates un-offset objects,
     # and subsequent tuples are offset by t_i for each index in the tuple.
     self.lithoDict['substrate'] = {(): []}
     # To start, we need to collect up all the lithography directives, and
     # organize them by layerNum and objectIDs within layers.
     baseSubstratePartNames = []
     for partName in self.model.modelDict['3DParts'].keys():
         partDict = self.model.modelDict['3DParts'][partName]
         # If this part is a litho step
         if 'lithography' == partDict['directive']:
             layerNum = partDict['layerNum']  # layerNum of this part
             # Add the layerNum to the layer dictionary:
             if layerNum not in self.lithoDict['layers']:
                 self.lithoDict['layers'][layerNum] = {'objIDs': {}}
             layerDict = self.lithoDict['layers'][layerNum]
             # Gennerate the base and thickness of the layer:
             layerBase = self._fetch_geo_param(partDict['z0'])
             layerThickness = self._fetch_geo_param(partDict['thickness'])
             # All parts within a given layer number are required to have
             # identical thickness and base, so check that:
             if 'base' in layerDict:
                 assert layerBase == layerDict['base']
             else:
                 layerDict['base'] = layerBase
             if 'thickness' in layerDict:
                 assert layerThickness == layerDict['thickness']
             else:
                 layerDict['thickness'] = layerThickness
             # A given part references a base sketch. However, we need to split
             # the sketch here into possibly disjoint sub-sketches to work
             # with them:
             sketch = self.doc.getObject(partDict['fcName'])
             splitSketches = splitSketch(sketch)
             for mySplitSketch in splitSketches:
                 objID = len(layerDict['objIDs'])
                 objDict = {}
                 objDict['partName'] = partName
                 objDict['sketch'] = mySplitSketch
                 self.trash.append(mySplitSketch)
                 self.lithoDict['layers'][layerNum]['objIDs'][
                     objID] = objDict
             # Add the base substrate to the appropriate dictionary
             baseSubstratePartNames += partDict['lithoBase']
     # Get rid of any duplicates:
     baseSubstratePartNames = list(set(baseSubstratePartNames))
     # Now convert the part names for the substrate into 3D freeCAD objects, which
     # should have already been rendered.
     for baseSubstratePartName in baseSubstratePartNames:
         for baseSubstrateObjName in self.model.modelDict['3DParts'][
                 baseSubstratePartName]['fileNames'].keys():
             self.lithoDict['substrate'][()] += [
                 self.doc.getObject(baseSubstrateObjName)
             ]
     # Now that we have ordered the primitives, we need to compute a few
     # aux quantities that we will need. First, we compute the total bounding
     # box of the lithography procedure:
     thicknesses = []
     bases = []
     for layerNum in self.lithoDict['layers'].keys():
         thicknesses.append(self.lithoDict['layers'][layerNum]['thickness'])
         bases.append(self.lithoDict['layers'][layerNum]['base'])
     bottom = min(bases)
     totalThickness = sum(thicknesses)
     assert len(self.lithoDict['substrate'][
         ()]) > 0  # Otherwise, we don't have a reference for the lateral BB
     substrateUnion = genUnion(self.lithoDict['substrate'][()],
                               consumeInputs=False)  # total substrate
     BB = list(getBB(substrateUnion))  # bounding box
     BB[4] = min([bottom, BB[4]])
     BB[5] = max([BB[5] + totalThickness, bottom + totalThickness])
     BB = tuple(BB)
     constructionZone = makeBB(BB)  # box that encompases the whole domain.
     self.lithoDict['boundingBox'] = [BB, constructionZone]
     delete(substrateUnion)  # not needed for next steps
     delete(constructionZone)  # not needed for next steps
     # Next, we add two prisms for each sketch. The first, which we denote "B",
     # is bounded by the base from the bottom and the layer thickness on the top.
     # These serve as "stencils" that would be the deposited shape if no other.
     # objects got in the way. The second set of prisms, denoted "C", covers the
     # base of the layer to the top of the entire domain box. This is used for
     # forming the volumes occupied when substrate objects are offset and
     # checking for overlaps.
     for layerNum in self.lithoDict['layers'].keys():
         base = self.lithoDict['layers'][layerNum]['base']
         thickness = self.lithoDict['layers'][layerNum]['thickness']
         for objID in self.lithoDict['layers'][layerNum]['objIDs']:
             sketch = self.lithoDict['layers'][layerNum]['objIDs'][objID][
                 'sketch']
             B = extrudeBetween(sketch, base, base + thickness)
             C = extrudeBetween(sketch, base, BB[5])
             self.lithoDict['layers'][layerNum]['objIDs'][objID]['B'] = B
             self.lithoDict['layers'][layerNum]['objIDs'][objID]['C'] = C
             self.trash.append(B)
             self.trash.append(C)
             # In addition, add a hook for the HDict, which will contain the "H"
             # constructions for this object, but offset to thicknesses of various
             # layers, according to the keys.
             self.lithoDict['layers'][layerNum]['objIDs'][objID][
                 'HDict'] = {}