Dienstag, 11. November 2008

Building a dynamic tool for input of solar energy economic variables

I've always been inspired by SimCity and The Sims, and wondered how we could use these "games" for more important work -- particularly the design of "Solar Cities". Inspired by the folks at Digital Urban, I tried my hand at building a virtual Egyptian Darb Al Ahmar community in the "Oblivion" Game Engine and then placing solar panels on a couple of the roofs there.

You can see my results below:




and

.

I also tried my hand at using Google Sketchup to create a tutorial for how to adjust our solar hot water system on the Zabaleen school in Muqattam:




Then I discovered Metroquest , the first serious SimCity oriented planning tool.



While it isn't a 3D virtual reality tool, it does a great job of helping planners create future scenarios for evaluation by stakeholders. There are fascinating examples of its use in Yellowknife
and Niagra that you can work through to see how effective the tool is.

The question now is, how do we develop a similar tool for Solar CITIES?

Flash MX may hold part of the answer, so we will start here.

One of the great features of MetroQuest is their use of sliders as input mechanisms. I have long argued (and most recently do so in my Ph.D. thesis) that urban planning should be like mixing a song, working to achieve a harmonious balance of all the elements that make living in cities worthwhile and desirable. My postmodern professor Ed Soja at UCLA, author of "Thirdspace", challenged us to move beyond the binary logic of "either/or" and into the hybridity friendly thirdspace of "both-and". But he cautioned that both-and was not liscence to simply mash everything up.

Coming from a music industry background, I was always comfortable with both-and, finding that the way to achieve beauty was through the proper mix. I have worked on enough mixing boards over the years to appreciate the subtlety and importance of "faders", tweaking the amount of bass and drums and synth pads and vocals until something great came out of the mix.

So when developing a tool to help calculate the costs and infrastructure parameters of effective solar energy set-ups, I knew one of the first tasks I would have to undertake would be figuring out how to create and use faders in Flash.

Fortunately, http://www.maximized.co.uk/flashintro/slider1.html has a great little tutorial with the necessary code in it.

I'll reproduce the code here; for the tutorial click the link above.









  • Open this Button Movie Clip for editing, select the button symbol that is embedded in it, then add the following Actionscript code to the button:







    on (press) {
    startDrag("", false, left, top, right, bottom);
    dragging = true;
    }
    
    on (release, releaseOutside) {
    stopDrag();
    dragging = false;
    }
    














  • Go back to the main Timeline and select the Button Movie Clip. Add the following Actionscript code to the Button Movie Clip:







    onClipEvent (load) {
    top = _y;
    bottom = top + 100;
    left = _x;
    right = _x;
    }
    
    onClipEvent (enterFrame) {
    if (dragging == true) {
    // execute this code
    }
    }
    
    



    They say at the end of the tutorial: " To get the button to do something, look back at the second section of code you added - any code you place in the section marked // execute this code will be executed while the slider is being dragged.
    One thing you should try is to use the slider to control the volume of a music clip. Create a sound object and set it to play continuously. Add a slider to your Flash movie and add code so that it will alter the volume of the sound when it is dragged. Hint: the slider can move up and down in a range of 100 pixels. Sound volume has a range of zero (lowest volume) to 100 (highest volume)."


    So that is a great start!

    But if you are a non-programmer like me, you have no idea how to build the code to add functionality. Fortunately there are some other great tutorials, like this one from http://www.kirupa.com/developer/mx/slider.htm

    The relevant code is:


    this.ratio=0 ;
    dragger.onPress=function(){
    this.startDrag(true,0,0,line._width,0);
    this.onEnterFrame=function(){
    ratio=Math.round(this._x) ;
    }
    }
    dragger.onRelease=dragger.onReleaseOutside=stopDrag;
    or this:


    this.ratio=0 ;
    dragger.onPress=function(){
    this.startDrag(true,0,0,line._width,0);
    this.onEnterFrame=function(){
    ratio=Math.round(this._x*100/line._width) ;
    }
    }
    dragger.onRelease=dragger.onReleaseOutside=stopDrag;

    Now we can use the slider to output ratios from 1 to 100, great for percents!

    GET URL


    One thing we want to be able to do in the program is to make us of the California Solar Initiative Incentive Calculator found at http://www.csi-epbb.com/.  So we need to create a button in flash that calls that website.

    The simple action to attach to the button is


    on(release){getURL("http://www.csi-epbb.com/");
    }


    (You can find functions like "getURL"  by clicking on the + sign under actions at opening "Global Functions" and then "Browser/Network". Make sure you put them after the on(release) command.)



    The only problem is that though the .swf launches a browser when testing on your desktop, when you upload the .swf to a website and click on the button it launches the url in the same window.  This can be a hassle if you are doing on-line training as we are and you want the user to be able to simultaneously view the flash document AND the website the URL reffered to.

    What to do?

    According to ShawnJC:

    "Something you all might be interested. I've been using similar javascript to open windows for some time now, but recently have found out that the new SP2 upgrade for windows XP will install a pop-up blocker by default that blocks a window opened with javascript from a signal from Flash even though it is a user inituated click. I've been trying different things and found that the only way I can get a window to open with Flash that the XP pop-up blocker won't block is with the basic GETURL ("website","_blank") method. So anyway, might wanna test that out if you plan on using Flash and Javascript to open windows..."

    So now my code reads:  on(release){getURL("http://www.csi-epbb.com/", "_blank");
    }  and it works great!

    But wait, there's more!

    The only dissatisfaction I have with using the "_blank" command is that I often already have too many tabs open on my browser (I use Firefox, and I LOVE the new tab feature, but for keeping people involved in a web-based training program it can be distracting to have to keep clicking on different tabs wondering where on the far right of the screen that particular browser window went!) So I want to be able to open the url in a new window (like a popup).

    The code to do that is found here: http://www.actionscript.org/resources/articles/22/1/Pop-Up-window-within-flash/Page1.html

    The basic idea is that you replace on(release){getURL("http://www.csi-epbb.com/", "_blank");
    }
    with a piece of Java Script that looks like this:

     on (release) {
        getURL ("javascript:openNewWindow('http://www.csi-epbb.com/','thewin','height=600,width=800,toolbar=yes,scrollbars=yes');");
    }

    Note that instead of using double quotes in the javascript you use single quote marks.  You can decide if you want the user to have toolbar access (so they can use the window you created to go elsewhere) or scrollbars.  I set them to yes because I like giving people freedom. Vive la liberte!  You can also set the height and width. I like my pop-ups fairly large but not overwhelming.

    All fine and good; it works with the .swf file.  What about opening applications, like Google Earth?

    Opening Applications

    Here I encountered a lot of problems. Seems that somebody created a flash virus once upon a time and so, to protect users from these, the way flash handles functions that call .exe files has been changed.
    But an explanation of how to run files is found here:
    http://www.northcode.com/blog.php/2007/08/07/Conquering-FSCommand-EXEC-Part-1-Proxy

    What I learned to do is to create a folder called "fscommand" in the folder that contains my .fla source file and my .swf.

    Inside that folder I used notepad to create a text document that held this text:

    "C:\Program Files\Google\Google Earth\googleearth.exe" (because that is where Google Earth is on my computer)

    I saved the file and then changed the extension from .txt to .bat.  I called the file "openGoogleEarth.bat".  When I click on it I notice it launches a DOS command window and then launches the program. All fine and good.
    Then, in flash, in my action script for the button I put the following:

    on(release)  {
        fscommand("exec", "openGoogleEarth.bat");
    }

    I notice when I test the movie it does nothing.  But if I PUBLISH the movie as a Windows Projector (an  .EXE file)  as well as an .swf (you find these options under File/Publish Settings) the windows projector will let me launch Google Earth with that button.  The .swf file, however, does nothing.

    I also downloaded a nice little app called proxy.exe that hides the black DOS box.  The trick there was to place "proxy.exe" in the fscommand folder and then rename it "openGoogleEarth.exe" (or whatever name your bat file has.Then IT calls the .bat file which then calls the program.  (You can get better instructions here: http://www.northcode.com/blog.php/2007/08/07/Conquering-FSCommand-EXEC-Part-1-Proxy)


    Thanks to a Swedish forum user named j0h@nB we get the following advice:


    1. A.swf has to be an exe-file, that is, export it as a Flash projector (A.exe)
    2. B.exe has to reside in subfolder fscommand. So, if A.exe is saved in folder C:\somefolder\, then B.exe has to be saved in C:\somefolder\fscommand
    3. You should then be able to use fscommand to execute B.exe as follows...





    Code:
    on(release){
          fscommand("exec","B.exe");
    }

     What about opening files on Macs as well as PCs?

    I turned to this website, http://www.northcode.com/ , for the following advice for how to prepare for cross platform functionality:


    Northcode says the following:


    "If you want to be a little smarter about it you can replace the fscommand exec calls with something like my SmartExec function below.

    SmartExec will figure out what platform it's running on and launch the correct helper to open the target file. The trick is to give your helper applications names that are similar to the file you're trying to open.

    thefile.pdf - name of the file you want to open
    thefile.exe - EXE helper app that opens thefile.pdf on Windows
    thefile_script - AppleScript the opens thefile.pdf on the Mac

    Now to open thefile.pdf you just put SmartExec("thefile"); in your button release events and SmartExec figures out which application to run based on the platform and the helper application does all the work.





    Code:
    function SmartExec(target)
    {
       platform = substring(getVersion(), 1,3);
     
       if (platform == "WIN") 
       {
          // we're running on Windows, target an EXE file
          fscommand("exec", target + ".exe");
       } 
       else 
       {
          // we're running on a MAC, target an AppleScript file
          fscommand("exec", target + "_script");
       }
    }
    There's an article on my blog "Conquering FSCommand EXEC Part 1 : Proxy" that describes how to use a free tool I created and BAT files to open files on a Windows system. If you're using Flash CS3 then you'll also want to have a look at this article FSCommand EXEC is Broken in Flash CS3.

    On the Mac, you would use a compiled AppleScript instead of the BAT file and EXE combination. Like the Windows solution you'll need an AppleScript for each file that you want to open. You can use this script as a tempate.




    Code:
    --set the name of the file to open 
    
    property fileName : "thefile.pdf"
    
    --get the path to the containing folder 
    
    set myPath to (path to me as string)
    set AppleScript's text item delimiters to ":"
    set the parentFolder to ¬
       ((text items 1 thru -2 of myPath) & "") as string
    set AppleScript's text item delimiters to ""
    
    -- find the file and open it 
    
    try
       set targetFile to alias (the parentFolder & fileName)
    on error
       --ie if there's no  file here by this name, it will quit. 
       return quit
    end try
    
    tell application "Finder"
       open file targetFile
    end tell

    I cut and paste Northcode's  SmartExec function into my actions layer and tested it on the PC and it seems to work great. Thanks Northcode!


  • Keine Kommentare: