Skip to content
Snippets Groups Projects
object_laplace_lightning.py 42.1 KiB
Newer Older
  • Learn to ignore specific revisions
  •     cList = splitList(aList, 0)
        oList = splitList(aList, 1)
        Omin, Omax = getLowHigh(oList)
    
        if Omin == Omax:
            Omax += notZero
            Omin -= notZero
    
        PdL = []
        E = notZero
        minL = [Omin for q in range(len(oList))]
        maxL = [Omax for q in range(len(oList))]
        uNL = [uN for q in range(len(oList))]
        E = sum(map(fslg_e13, oList, minL, maxL, uNL))
        EL = [E for q in range(len(oList))]
        mp = map(fslg_e12, oList, minL, maxL, uNL, EL)
    
        for m in mp:
            PdL.append(m)
    
        return PdL
    
    
    def updatePointCharges(p, cList, eList=[]):
    
        # In: pNew - new growth cell
        # cList - old candidate sites, eList -SAME
        # Out: list of new charge at candidate sites
    
        r1 = 1 / 2        # (FSLG - Eqn. 10)
        nOiL = []
    
        for oi in range(len(cList)):
            o = cList[oi][1]
            c = cList[oi][0]
            iOe = 0
            rit = dist(c[0], c[1], c[2], p[0], p[1], p[2])
            iOe += (1 - (r1 / rit))
            Oit = o + iOe
            nOiL.append((c, Oit))
    
        return nOiL
    
    
    def initialPointCharges(pList, cList, eList=[]):
    
        # In: p -CHARGED CELL (XYZ), cList -candidate sites (XYZ, POT, PROB)
        # Out: cList -with potential calculated
    
        r1 = 1 / 2        # (FSLG - Eqn. 10)
        npList = []
    
        for p in pList:
            npList.append(((p[0], p[1], p[2]), 1.0))
    
        for e in eList:
            npList.append(((e[0], e[1], e[2]), e[3]))
    
        OiL = []
        for i in cList:
            Oi = 0
            for j in npList:
                if i != j[0]:
                    rij = dist(i[0], i[1], i[2], j[0][0], j[0][1], j[0][2])
    
                    Oi += (1 - (r1 / rij)) * j[1]  # charge influence
    
            OiL.append(((i[0], i[1], i[2]), Oi))
    
        return OiL
    
    
    def getCandidateSites(aList, iList=[]):
    
        # In: aList -(X,Y,Z) of charged cell sites, iList - insulator sites
        # Out: candidate list of growth sites [(X,Y,Z)]
    
        cList = []
        for c in aList:
            tempList = getStencil3D_26(c[0], c[1], c[2])
            for t in tempList:
                if t not in aList and t not in iList:
                    cList.append(t)
        ncList = deDupe(cList)
    
        return ncList
    
    
    
        winmgr = bpy.context.scene.advanced_objects1
    
        oOB = bpy.data.objects.new('ELorigin', None)
        oOB.location = ((0, 0, 10))
        bpy.context.scene.objects.link(oOB)
    
        gOB = bpy.data.objects.new('ELground', None)
        gOB.empty_draw_type = 'ARROWS'
        bpy.context.scene.objects.link(gOB)
    
        cME = makeMeshCube(1)
        cOB = bpy.data.objects.new('ELcloud', cME)
        cOB.location = ((-2, 8, 12))
        cOB.hide_render = True
        bpy.context.scene.objects.link(cOB)
    
        iME = makeMeshCube(1)
        for v in iME.vertices:
            xyl = 6.5
            zl = .5
            v.co[0] = v.co[0] * xyl
            v.co[1] = v.co[1] * xyl
            v.co[2] = v.co[2] * zl
        iOB = bpy.data.objects.new('ELinsulator', iME)
        iOB.location = ((0, 0, 5))
        iOB.hide_render = True
        bpy.context.scene.objects.link(iOB)
    
        try:
            winmgr.OOB = 'ELorigin'
            winmgr.GOB = 'ELground'
            winmgr.COB = 'ELcloud'
            winmgr.IOB = 'ELinsulator'
        except:
            pass
    
    
    def checkSettings():
        check = True
    
        winmgr = bpy.context.scene.advanced_objects1
    
            message = "Error: no origin object selected"
    
        if winmgr.GROUNDBOOL and winmgr.GOB == "":
    
            message = "Error: no ground object selected"
    
        if winmgr.CLOUDBOOL and winmgr.COB == "":
    
            message = "Error: no cloud object selected"
    
        if winmgr.IBOOL and winmgr.IOB == "":
    
            message = "Error: no insulator object selected"
    
        if check is False:
            debug_prints(func="checkSettings", text=message)
    
        # return state and the message for the operator report
        return check, message
    
    
    # Main
    
        winmgr = bpy.context.scene.advanced_objects1
    
        # fast simulation of laplacian growth
        debug_prints(func="FSLG",
                     text="Go go gadget: fast simulation of laplacian growth")
    
        tc1 = time.clock()
        TSTEPS = winmgr.TSTEPS
    
        obORIGIN = bpy.context.scene.objects[winmgr.OOB]
        obGROUND = bpy.context.scene.objects[winmgr.GOB]
        winmgr.ORIGIN = obORIGIN.location
        winmgr.GROUNDZ = int((obGROUND.location[2] - winmgr.ORIGIN[2]) / winmgr.GSCALE)
    
    
        # 1) insert intial charge(s) point (uses verts if mesh)
    
        if obORIGIN.type == 'MESH':
    
            debug_prints(
                    func="FSLG",
                    text="Origin object is mesh, 'voxelizing' intial charges from verts"
                    )
    
            cgrid = voxelByVertex(obORIGIN, winmgr.GSCALE)
    
                debug_prints(
                    func="FSLG",
                    text="Cannot classify stroke from vert origins yet, no multi-mesh output"
                    )
    
                winmgr.VMMESH = False
                winmgr.VSMESH = True
    
    
        # ground charge cell / insulator lists (echargelist/iclist)
    
        eChargeList = []
        icList = []
        if winmgr.GROUNDBOOL:
            eChargeList = fakeGroundChargePlane(winmgr.GROUNDZ, winmgr.GROUNDC)
    
            debug_prints(
                    func="FSLG",
                    text="'Voxelizing' cloud object (could take some time)"
                    )
    
            obCLOUD = bpy.context.scene.objects[winmgr.COB]
            eChargeListQ = voxelByRays(obCLOUD, winmgr.ORIGIN, winmgr.GSCALE)
            eChargeList = addCharges(eChargeListQ, winmgr.CLOUDC)
    
            debug_prints(
                    func="FSLG",
                    text="cloud object cell count", var=len(eChargeList)
                    )
    
    
            debug_prints(
                    func="FSLG",
                    text="'Voxelizing' insulator object (could take some time)"
                    )
    
            obINSULATOR = bpy.context.scene.objects[winmgr.IOB]
            icList = voxelByRays(obINSULATOR, winmgr.ORIGIN, winmgr.GSCALE)
    
    
            debug_prints(
                    func="FSLG",
                    text="Insulator object cell count", var=len(icList)
                    )
    
        # 2) locate candidate sites around charge
    
        cSites = getCandidateSites(cgrid, icList)
    
    
        # 3) calc potential at each site (eqn. 10)
    
        cSites = initialPointCharges(cgrid, cSites, eChargeList)
    
        ts = 1
        while ts <= TSTEPS:
    
            # 1) select new growth site (eqn. 12)
            # get probabilities at candidate sites
    
            gProbs = getGrowthProbability(winmgr.BIGVAR, cSites)
    
            # choose new growth site based on probabilities
    
            gSitei = weightedRandomChoice(gProbs)
            gsite = cSites[gSitei][0]
    
    
            # 2) add new point charge at growth site
            # add new growth cell to grid
    
            # remove new growth cell from candidate sites
    
            cSites.remove(cSites[gSitei])
    
    
            # 3) update potential at candidate sites (eqn. 11)
    
            cSites = updatePointCharges(gsite, cSites, eChargeList)
    
    
            # 4) add new candidates surrounding growth site
            # get candidate 'stencil'
    
            ncSitesT = getCandidateSites([gsite], icList)
    
            # remove candidates already in candidate list or charge grid
    
            ncSites = []
            cSplit = splitList(cSites, 0)
            for cn in ncSitesT:
                if cn not in cSplit and cn not in cgrid:
                    ncSites.append((cn, 0))
    
    
            # 5) calc potential at new candidate sites (eqn. 10)
    
            ncSplit = splitList(ncSites, 0)
            ncSites = initialPointCharges(cgrid, ncSplit, eChargeList)
    
    
            # add new candidate sites to candidate list
    
            for ncs in ncSites:
                cSites.append(ncs)
    
    
            istr1 = ':::T-STEP: ' + str(ts) + '/' + str(TSTEPS)
            istr12 = ' | GROUNDZ: ' + str(winmgr.GROUNDZ) + ' | '
            istr2 = 'CANDS: ' + str(len(cSites)) + ' | '
            istr3 = 'GSITE: ' + str(gsite)
    
            debug_prints(
                    func="FSLG",
                    text="Iteration complete",
                    var=istr1 + istr12 + istr2 + istr3
                    )
    
            # early termination for ground/cloud strike
    
            if winmgr.GROUNDBOOL:
                if gsite[2] == winmgr.GROUNDZ:
                    ts = TSTEPS + 1
    
                    debug_prints(
                            func="FSLG",
                            text="Early termination due to groundstrike"
                            )
    
            if winmgr.CLOUDBOOL:
                if gsite in splitListCo(eChargeList):
                    ts = TSTEPS + 1
    
                    debug_prints(
                            func="FSLG",
                            text="Early termination due to cloudstrike"
                            )
    
                    continue
    
        tc2 = time.clock()
        tcRUN = tc2 - tc1
    
        debug_prints(
                func="FSLG",
                text="Laplacian growth loop completed",
                var=str(len(cgrid)) + " / " + str(tcRUN)[0:5] + " Seconds"
                )
        debug_prints(func="FSLG", text="Visualizing data")
    
    
        reportSTRING = getReportString(tcRUN)
    
    
        # Visualize array
        visualizeArray(
                cgrid, obORIGIN, winmgr.GSCALE,
                winmgr.VMMESH, winmgr.VSMESH,
                winmgr.VCUBE, winmgr.VVOX, reportSTRING
                )
    
        debug_prints(func="FSLG", text="COMPLETE")
    
    class runFSLGLoopOperator(Operator):
    
        bl_idname = "object.runfslg_operator"
        bl_label = "run FSLG Loop Operator"
    
        bl_description = "By The Mighty Hammer Of Thor!!!"
    
    
        def execute(self, context):
    
            # tuple - state, report text
            is_conditions, message = checkSettings()
    
            if is_conditions:
    
                self.report({'WARNING'}, message + " Operation Cancelled")
    
                return {'CANCELLED'}
    
    
    class setupObjectsOperator(Operator):
    
        bl_idname = "object.setup_objects_operator"
        bl_label = "Setup Objects Operator"
    
        bl_description = "Create origin/ground/cloud/insulator objects"
    
    
        def execute(self, context):
            setupObjects()
    
    class OBJECT_PT_fslg(Panel):
    
        bl_label = "Laplacian Lightning"
        bl_space_type = "VIEW_3D"
        bl_region_type = "TOOLS"
        bl_context = "objectmode"
        bl_category = "Create"
        bl_options = {'DEFAULT_CLOSED'}
    
        def draw(self, context):
            layout = self.layout
    
            winmgr = context.scene.advanced_objects1
    
    
            col = layout.column(align=True)
            col.prop(winmgr, "TSTEPS")
            col.prop(winmgr, "GSCALE")
            col.prop(winmgr, "BIGVAR")
    
            col = layout.column()
            col.operator("object.setup_objects_operator", text="Create Setup objects")
            col.label("Origin object")
            col.prop_search(winmgr, "OOB", context.scene, "objects")
    
            box = layout.box()
            col = box.column()
            col.prop(winmgr, "GROUNDBOOL")
            if winmgr.GROUNDBOOL:
                col.prop_search(winmgr, "GOB", context.scene, "objects")
                col.prop(winmgr, "GROUNDC")
    
            box = layout.box()
            col = box.column()
            col.prop(winmgr, "CLOUDBOOL")
            if winmgr.CLOUDBOOL:
                col.prop_search(winmgr, "COB", context.scene, "objects")
                col.prop(winmgr, "CLOUDC")
    
            box = layout.box()
            col = box.column()
            col.prop(winmgr, "IBOOL")
            if winmgr.IBOOL:
                col.prop_search(winmgr, "IOB", context.scene, "objects")
    
            col = layout.column()
            col.operator("object.runfslg_operator",
                         text="Generate Lightning", icon="RNDCURVE")
    
            row = layout.row(align=True)
            row.prop(winmgr, "VMMESH", toggle=True)
            row.prop(winmgr, "VSMESH", toggle=True)
            row.prop(winmgr, "VCUBE", toggle=True)
    
        winmgr = bpy.context.scene.advanced_objects1
    
        rSTRING1 = 't:' + str(winmgr.TSTEPS) + ',sc:' + str(winmgr.GSCALE)[0:4] + ',uv:' + str(winmgr.BIGVAR)[0:4] + ','
        rSTRING2 = 'ori:' + str(winmgr. ORIGIN[0]) + '/' + str(winmgr. ORIGIN[1]) + '/' + str(winmgr. ORIGIN[2]) + ','
        rSTRING3 = 'gz:' + str(winmgr.GROUNDZ) + ',gc:' + str(winmgr.GROUNDC) + ',rtime:' + str(int(rtime))
        return rSTRING1 + rSTRING2 + rSTRING3
    
    
    def addReportProp(ob, str):
        bpy.types.Object.FSLG_REPORT = bpy.props.StringProperty(
            name='fslg_report', default='')
        ob.FSLG_REPORT = str
    
    
    def register():
        bpy.utils.register_class(runFSLGLoopOperator)
        bpy.utils.register_class(setupObjectsOperator)
        bpy.utils.register_class(OBJECT_PT_fslg)
    
    
    def unregister():
        bpy.utils.unregister_class(runFSLGLoopOperator)
        bpy.utils.unregister_class(setupObjectsOperator)
        bpy.utils.unregister_class(OBJECT_PT_fslg)
    
    
    if __name__ == "__main__":
        register()
        pass
    
    
    
        debug_prints(func="BENCH", text="BEGIN BENCHMARK")
    
        tsize = 25
        tlist = []
        for x in range(tsize):
            for y in range(tsize):
                for z in range(tsize):
                    tlist.append((x, y, z))
                    tlist.append((x, y, z))
    
    
        bt1 = time.clock()
        bt2 = time.clock()
        btRUNb = bt2 - bt1
        btRUNa = bt1 - bt0
    
    
        debug_prints(func="BENCH", text="SETUP TIME", var=btRUNa)
        debug_prints(func="BENCH", text="BENCHMARK TIME", var=btRUNb)
        debug_print_vars(
                "\n[BENCH]\n",
                "GRIDSIZE: ", tsize, ' - ', tsize * tsize * tsize
                )