I recently had almost the exact same use case:

 - On saving a custom post type, check for the existance of some meta data.
 - If it exists, geocode it using the Google Geocode API.
 - Save the result as a new meta field (this one hidden so the user can't screw it up).
 - *Note: What I do with the data on the front end of the site is handled in a template file using javascript and the Google Maps API.*

It looks like you're assembling multiple fields to get the address (I stored it in one) and you're saving the resulting format differently, but hopefully this serves as a good example that you can borrow from. As I always try to do, I used the WordPress API functions for querying and saving to the database. It's mores secure and future-proof.

Just as @OriginalEXE suggests, I used the [`save_post` hook][1]. I don't think you need `publish_post`:

> save_post is an action triggered whenever a post or page is created or updated, which could be from an import, post/page edit form, xmlrpc, or post by email.

A few more notes:

 - Note the lower priority of the action. I found that leaving it as the default priority left it looking at the previously saved data (which is saved using Advanced Custom Fields which it looks like you're using).
 - The geocoding class was not mine and saved me a huge amount of time. I modified what Sergiy published to use the `wp_remote_get()` function that has better server support than either `curl` or `file_get_contents`. It uses the JSON (Google-recommended) request rather than XML.

I put this in a functionality plugin, but it would work the same in `functions.php`:


    /* function wc_add_latlong()
     * take address from post, geocode it, and save as a custom meta field
     * @parameter $post_id, id of the post being saved, passed by save_post hook
     * @returns nothing
     **************************************/
    function wc_add_latlong( $post_id ) {
        // get the address from ACF field
    	$address = get_field( 'wc_map_address', $post_id );
        // Check to see if the post type is right, it's not a revision, and there is an address to geocode
    	if( get_post_type( $post_id ) == 'wc_biz' && !wp_is_post_revision( $post_id ) && $address ) {
    		// call the geocoder class below
    		$coords = geocoder::getLocation( $address );
    		// split latLngObject with a comma and space
    		$lat_long_string = $coords['lat'] . ', ' . $coords['lng'];
    		// either add that value as a new post meta field OR update the existing one
    		add_post_meta( $post_id, '_wc_lat_long', $lat_long_string, true ) || update_post_meta( $post_id, '_wc_lat_long', $lat_long_string );
    	}
    }
    // This runs on the save_post hook
    add_action( 'save_post', 'wc_add_latlong', 11 );
    
    // Thank you Sergiy!
    // http://erlycoder.com/45/php-server-side-geocoding-with-google-maps-api-v3
    // a class to get the lat and long of an address _server-side_
    class geocoder{
        // The base URL for a non-sensor json Google Geocode API request
    	static private $url = "http://maps.google.com/maps/api/geocode/json?sensor=false&address=";
    
    	static public function getLocation($address){
    		// append URL-friendly address to base URL
    		$url = self::$url.urlencode($address);
    	        // request the Geocode JSON object from Google
    		$resp_json = wp_remote_get($url);
                // decode the body of the response
    		$resp = json_decode( wp_remote_retrieve_body($resp_json), true );
                // make sure the remove_get was successful and it geocoded the address
    		if( !is_wp_error( $resp_json ) && $resp['status']='OK' ) {
    		        // success! return the lat and long
    			return $resp['results'][0]['geometry']['location'];
    		}else{
    		    	// we failed, return false
    			return false;
    		}
    	}
    }

UPDATE: I've commented all the code so you can understand what's going on. You'll have to adapt it from there.

  [1]: http://codex.wordpress.org/Plugin_API/Action_Reference/save_post