// A static class for converting between Decimal and DMS formats for a location
// ported from: http://andrew.hedges.name/experiments/convert_lat_long/
// Decimal Degrees = Degrees + minutes/60 + seconds/3600
// more info on formats here: http://www.maptools.com/UsingLatLon/Formats.html
// use: LocationFormatter.DMSToDecimal( 45, 35, 38, LocationFormatter.SOUTH );
// or: LocationFormatter.decimalToDMS( -45.59389 );
function LocationFormatter(){
};
LocationFormatter.NORTH = 'N';
LocationFormatter.SOUTH = 'S';
LocationFormatter.EAST = 'E';
LocationFormatter.WEST = 'W';
LocationFormatter.roundToDecimal = function( inputNum, numPoints ) {
var multiplier = Math.pow( 10, numPoints );
return Math.round( inputNum * multiplier ) / multiplier;
};
LocationFormatter.decimalToDMS = function( location, hemisphere ){
if( location < 0 ) location *= -1; // strip dash '-'
var degrees = Math.floor( location ); // strip decimal remainer for degrees
var minutesFromRemainder = ( location - degrees ) * 60; // multiply the remainer by 60
var minutes = Math.floor( minutesFromRemainder ); // get minutes from integer
var secondsFromRemainder = ( minutesFromRemainder - minutes ) * 60; // multiply the remainer by 60
var seconds = LocationFormatter.roundToDecimal( secondsFromRemainder, 2 ); // get minutes by rounding to integer
return degrees + '° ' + minutes + "' " + seconds + '" ' + hemisphere;
};
LocationFormatter.decimalLatToDMS = function( location ){
var hemisphere = ( location < 0 ) ? LocationFormatter.SOUTH : LocationFormatter.NORTH; // south if negative
return LocationFormatter.decimalToDMS( location, hemisphere );
};
LocationFormatter.decimalLongToDMS = function( location ){
var hemisphere = ( location < 0 ) ? LocationFormatter.WEST : LocationFormatter.EAST; // west if negative
return LocationFormatter.decimalToDMS( location, hemisphere );
};
LocationFormatter.DMSToDecimal = function( degrees, minutes, seconds, hemisphere ){
var ddVal = degrees + minutes / 60 + seconds / 3600;
ddVal = ( hemisphere == LocationFormatter.SOUTH || hemisphere == LocationFormatter.WEST ) ? ddVal * -1 : ddVal;
return LocationFormatter.roundToDecimal( ddVal, 5 );
};
A collection of handy code snippets in the languages that I use on a daily basis.
July 26, 2011
Javascript: Formatting latitude/longitude location between Decimal and DMS (degrees, minutes, seconds)
I'm working on a javascript UI for a mobile app that receives location data in the Decmial format. We wanted the fancy DMS format, so I found some code, rewrote it, and wrapped it up into a nice little static class for converting back and forth.
April 27, 2011
Webkit bug: translate3d positioning doesn't activate browser scrollbars
After some frustration in Safari and Mobile Safari, I found that by setting a -webkit-transform: translate3d() to position the y-coordinate of an html element beyond the browser window height, it will not cause the browser to activate its scrollbars. However, by switching to the web-standards css top style, this problem is alleviated. This seems like a browser bug to me.
Consider the following css, in both desktop and mobile Safari:
Consider the following css, in both desktop and mobile Safari:
<html>
<head>
<style>
.notbroken {
position:absolute;
top:10000px;
}
.broken {
position:absolute;
-webkit-transform: translate3d(0px, 10000px, 0px);
}
</style>
</head>
<body>
<div class="notbroken">Scrollbars, please.</div>
</body>
</html>
Both css classes position the div 10,000 pixels down the page, but if you use the .broken version, you won't get scrollbars, and you'll never be able to see the content.
April 19, 2011
Javascript: Handle touch gestures for pinch (scale) and rotation
I wrote a little class to handle pinch & rotate gestures on a web page in iOS. There's a bunch of event listener adding/removing, which can get a little messy, so this should help keep your code clean if you need to handle gestures.
Here's the class:
Here's the class:
function GestureCallback( element, endCallback, changeCallback ) {
this.element = element;
this.end_callback = endCallback;
this.change_callback = changeCallback;
this.scale = 1;
this.rotation = 0;
this.init();
}
GestureCallback.prototype.init = function() {
// scope functions for listener removal
var self = this;
this.gestureStart = function(e){ self.onGestureStart(e) };
this.gestureChange = function(e){ self.onGestureChange(e) };
this.gestureEnd = function(e){ self.onGestureEnd(e) };
// really no need to check for IE stupidness, but maybe they'll support gestures someday? oy.
if( this.element.attachEvent ) this.element.attachEvent( "touchstart", this.gestureStart ); else this.element.addEventListener( "touchstart", this.gestureStart, false );
if( this.element.attachEvent ) this.element.attachEvent( "gesturestart", this.gestureStart ); else this.element.addEventListener( "gesturestart", this.gestureStart, false );
};
GestureCallback.prototype.onGestureStart = function ( e ) {
if( this.element.attachEvent ) this.element.attachEvent( "gesturechange", this.gestureChange ); else this.element.addEventListener( "gesturechange", this.gestureChange, false );
if( this.element.attachEvent ) this.element.attachEvent( "gestureend", this.gestureEnd ); else this.element.addEventListener( "gestureend", this.gestureEnd, false );
};
GestureCallback.prototype.onGestureChange = function ( e ) {
this.scale = e.scale;
this.rotation = e.rotation;
if( this.change_callback ) this.change_callback( this.scale, this.rotation );
};
GestureCallback.prototype.onGestureEnd = function ( e ) {
if( this.element.detachEvent ) this.element.detachEvent( "gesturechange", this.gestureChange ); else this.element.removeEventListener( "gesturechange", this.gestureChange, false );
if( this.element.detachEvent ) this.element.detachEvent( "gestureend", this.gestureEnd ); else this.element.removeEventListener( "gestureend", this.gestureEnd, false );
this.scale = e.scale;
this.rotation = e.rotation;
if( this.end_callback ) this.end_callback( this.scale, this.rotation );
};
GestureCallback.prototype.dispose = function() {
if( this.element.attachEvent ) this.element.detachEvent( "touchstart", this.gestureStart ); else this.element.removeEventListener( "touchstart", this.gestureStart, false );
if( this.element.attachEvent ) this.element.detachEvent( "gesturestart", this.gestureStart ); else this.element.removeEventListener( "gesturestart", this.gestureStart, false );
this.element = null;
this.end_callback = null;
this.change_callback = null;
this.gestureStart = null;
this.gestureChange = null;
this.gestureEnd = null;
};
And the instantiation:var pinchCallback = new GestureCallback( yourElement, function( scale, rotation ){
console.log('done: '+scale+','+rotation);
if( scale < 1 ) {
// leave the section, since we've pinched it closed
}
}, function( scale, rotation ){
console.log('changing: '+scale+','+rotation);
});
And when you're done with your gesture needs, collect your garbage:
pinchCallback.dispose(); pinchCallback = null;
April 8, 2011
Processing: MovieMaker gotchas in Eclipse
I haven't touched my Processing sketches for a while, and got lots of weird errors while trying to render a video using the built-in MovieMaker object.
If you get the following error, you need to delete the previous rendered movie, or use some sort of timestamp to automatically name each new movie:
A stupid user-error error message I got was due to accidentally starting 2 instances of MovieMaker. Upon calling MovieMaker.finish(), I got this error:
Some other issues I've run into:
* Certain codecs won't be installed on your machine. For example, I can't use MovieMaker.H264, but I can use MovieMaker.ANIMATION
* After rendering a movie, Quicktime can have trouble playing it back, especially with certain codecs. My movies look blank. A workaround is to open and export the video from Quicktime Pro in order to view it.
Finally, something I've been doing with all my Processing sketches is to add the following VM Arguments to the Run Configuration. This helps avoid running out of memory and to run in 32-bit mode (required for certain operations):
Exception in thread "Animation Thread" java.lang.UnsatisfiedLinkError: quicktime.QTSession.Gestalt(I[I)S Caused by: java.lang.UnsatisfiedLinkError: /System/Library/Java/Extensions/libQTJNative.jnilib: no suitable image found. Did find: /System/Library/Java/Extensions/libQTJNative.jnilib: no matching architecture in universal wrapperThe above error was fixed by switching the JVM that Eclipse was using in the "Run..." configuration. On my Macbook, I simply switched to an alternate JVM 1.5, and it got rid of the problem:
If you get the following error, you need to delete the previous rendered movie, or use some sort of timestamp to automatically name each new movie:
The movie file already exists. Please delete it first.Here's a little timestamp code I wrote to help prevent file name conflicts:
_timestamp = "" + String.valueOf( p.year() ) + "-" + String.valueOf( p.month() ) + "-" + String.valueOf( p.day() ) + "-" + String.valueOf(p.hour()) + "-" + String.valueOf(p.minute()) + "-" + String.valueOf(p.second()); _mm = new MovieMaker( p, p.width, p.height, "output/render-"+_timestamp+".mov", _framesPerSecond, MovieMaker.ANIMATION, MovieMaker.HIGH );
A stupid user-error error message I got was due to accidentally starting 2 instances of MovieMaker. Upon calling MovieMaker.finish(), I got this error:
quicktime.std.StdQTException[QTJava:7.6.6g],-2014=invalidDuration,QT.vers:7668000
Some other issues I've run into:
* Certain codecs won't be installed on your machine. For example, I can't use MovieMaker.H264, but I can use MovieMaker.ANIMATION
* After rendering a movie, Quicktime can have trouble playing it back, especially with certain codecs. My movies look blank. A workaround is to open and export the video from Quicktime Pro in order to view it.
Finally, something I've been doing with all my Processing sketches is to add the following VM Arguments to the Run Configuration. This helps avoid running out of memory and to run in 32-bit mode (required for certain operations):
-d32 -Xmx1024M -Xms1024M
Labels:
bug,
itouch,
problems,
processing,
processing.org
February 21, 2011
Bash script: Harvest email addresses from a directory of files
I had to go through over a year of server logs to rescue newsletter signups that may or may not have been passed to our newsletter service, due to server updates that happened without my knowledge. I wrote a little command to scrape all the log files in my directory, and output a text file with all the addresses it found. Here we go:
# recursively(!) scrapes directories and prints out each email address to a new line
egrep -o -h -r '[a-zA-Z0-9_-\+\.]+@[a-zA-Z0-9_-\+\.]+?\.[a-zA-Z]{2,3}' *.* | sort | uniq > email_addresses.txt
Credit: I started with a command from Linux.com, and customized it until the output was correct, and nicely formatted.
Subscribe to:
Posts (Atom)

