I have difined my flow as:
builder.id("", PublisherBean.PUBLISHER_FLOW_NAME);
builder.viewNode("list", "/pages/publishers.xhtml");
builder.viewNode("details", "/pages/publishers-details.xhtml");
builder.viewNode("deleted", "/pages/publishers-deleted.xhtml");
builder.viewNode("form", "/pages/publishers-form.xhtml");
builder.viewNode("exit", "/index.xhtml");
builder.methodCallNode("invoke-update")
.expression("#{publisherBean.update()}")
.defaultOutcome("details");
builder.methodCallNode("switch-fail")
.defaultOutcome("invoke-publishers")
.expression("#{publisherBean.switchFail()}");
builder.switchNode("proceed-action-request")
.defaultOutcome("switch-fail")
.switchCase()
.condition("#{publisherBean.actionType.ifEdit()}").fromOutcome("form");
builder.switchNode("go-for-it")
.defaultOutcome("switch-fail")
.switchCase()
.switchCase()
.condition("#{publisherBean.actionType.ifEdit()}").fromOutcome("invoke-update");
as you can see, there is two switch nodes. First directs to a View Node, second one is trying to direct to a Method Call Node.
First one works fine, however second is giving me a headache. Second one is giving me an error
Unable to find matching navigation case with from-view-id '/pages/publishers-form.xhtml' for action '#{publisherBean.proceed()}' with outcome 'proceed-form'.
proceed function is just
public String proceed() {
LOG.log(Level.OFF, "Form proceed in action type {0}", actionType);
return "go-for-it";
}
Logged info confirms, that publisherBean.actionType.ifEdit() returns true, however that fact is ignored. If i change outcome from invoke-update to form or any other View Node id, then it "works fine".
Is it i'm doing something wrong, or Method Call Node cant be used as an outcome to a Switch Node?
I run into this issue too. In my case the problem is in calling Method Call Node after another Method Call Node.
I invesigated it a bit and found a problem in: com.sun.faces.application.NavigationHandlerImpl.synthesizeCaseStruct method. This method is used to determine where to go from methodCallNode or switchCallNode and it only looks at viewNodes and returnNodes.
private CaseStruct synthesizeCaseStruct(FacesContext context, Flow flow, String fromAction, String outcome) {
CaseStruct result = null;
FlowNode node = flow.getNode(outcome);
if (null != node) {
if (node instanceof ViewNode) {
result = new CaseStruct();
result.viewId = ((ViewNode)node).getVdlDocumentId();
result.navCase = new MutableNavigationCase(fromAction,
fromAction, outcome, null, result.viewId,
flow.getDefiningDocumentId(), null, false, false);
} else if (node instanceof ReturnNode) {
String fromOutcome = ((ReturnNode)node).getFromOutcome(context);
FlowHandler flowHandler = context.getApplication().getFlowHandler();
try {
flowHandler.pushReturnMode(context);
result = getViewId(context, fromAction, fromOutcome, FlowHandler.NULL_FLOW);
// We are in a return node, but no result can be found from that
// node. Show the last displayed viewId from the preceding flow.
if (null == result) {
Flow precedingFlow = flowHandler.getCurrentFlow(context);
if (null != precedingFlow) {
String toViewId = flowHandler.getLastDisplayedViewId(context);
if (null != toViewId) {
result = new CaseStruct();
result.viewId = toViewId;
result.navCase = new MutableNavigationCase(context.getViewRoot().getViewId(),
fromAction,
outcome,
null,
toViewId,
FlowHandler.NULL_FLOW,
null,
false,
false);
}
}
} else {
result.newFlow = FlowImpl.SYNTHESIZED_RETURN_CASE_FLOW;
}
}
finally {
flowHandler.popReturnMode(context);
}
}
} else {
// See if there is an implicit match within this flow, using outcome
// to derive a view id within this flow.
String currentViewId = outcome;
// If the viewIdToTest needs an extension, take one from the currentViewId.
String currentExtension;
int idx = currentViewId.lastIndexOf('.');
if (idx != -1) {
currentExtension = currentViewId.substring(idx);
} else {
// PENDING, don't hard code XHTML here, look it up from configuration
currentExtension = ".xhtml";
}
String viewIdToTest = "/" + flow.getId() + "/" + outcome + currentExtension;
ViewHandler viewHandler = Util.getViewHandler(context);
viewIdToTest = viewHandler.deriveViewId(context, viewIdToTest);
if (null != viewIdToTest) {
result = new CaseStruct();
result.viewId = viewIdToTest;
result.navCase = new MutableNavigationCase(fromAction,
fromAction, outcome, null, result.viewId,
null, false, false);
}
}
return result;
}
I am trying to do a simple CRUD app using Ember + Rails and I'm getting the following error when trying to go to the /workouts route.
Error while loading route: TypeError {} ember.js?body=1:415
Uncaught TypeError: Object function () {
if (!wasApplied) {
Class.proto(); // prepare prototype...
}
o_defineProperty(this, GUID_KEY, undefinedDescriptor);
o_defineProperty(this, '_super', undefinedDescriptor);
var m = meta(this), proto = m.proto;
m.proto = this;
if (initMixins) {
// capture locally so we can clear the closed over variable
var mixins = initMixins;
initMixins = null;
this.reopen.apply(this, mixins);
}
if (initProperties) {
// capture locally so we can clear the closed over variable
var props = initProperties;
initProperties = null;
var concatenatedProperties = this.concatenatedProperties;
for (var i = 0, l = props.length; i < l; i++) {
var properties = props[i];
Ember.assert("Ember.Object.create no longer supports mixing in other definitions, use createWithMixins instead.", !(properties instanceof Ember.Mixin));
for (var keyName in properties) {
if (!properties.hasOwnProperty(keyName)) { continue; }
var value = properties[keyName],
IS_BINDING = Ember.IS_BINDING;
if (IS_BINDING.test(keyName)) {
var bindings = m.bindings;
if (!bindings) {
bindings = m.bindings = {};
} else if (!m.hasOwnProperty('bindings')) {
bindings = m.bindings = o_create(m.bindings);
}
bindings[keyName] = value;
}
var desc = m.descs[keyName];
Ember.assert("Ember.Object.create no longer supports defining computed properties.", !(value instanceof Ember.ComputedProperty));
Ember.assert("Ember.Object.create no longer supports defining methods that call _super.", !(typeof value === 'function' && value.toString().indexOf('._super') !== -1));
Ember.assert("`actions` must be provided at extend time, not at create time, when Ember.ActionHandler is used (i.e. views, controllers & routes).", !((keyName === 'actions') && Ember.ActionHandler.detect(this)));
if (concatenatedProperties && indexOf(concatenatedProperties, keyName) >= 0) {
var baseValue = this[keyName];
if (baseValue) {
if ('function' === typeof baseValue.concat) {
value = baseValue.concat(value);
} else {
value = Ember.makeArray(baseValue).concat(value);
}
} else {
value = Ember.makeArray(value);
}
}
if (desc) {
desc.set(this, keyName, value);
} else {
if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) {
this.setUnknownProperty(keyName, value);
} else if (MANDATORY_SETTER) {
Ember.defineProperty(this, keyName, null, value); // setup mandatory setter
} else {
this[keyName] = value;
}
}
}
}
}
finishPartial(this, m);
this.init.apply(this, arguments);
m.proto = proto;
finishChains(this);
sendEvent(this, "init");
} has no method 'find'
My code is located here: https://github.com/ecl1pse/ember-workouts
What am I doing wrong?
Edit: Upon further investigation I believe the culprit is
EmberWorkouts.WorkoutsRoute = Ember.Route.extend(
model: -> EmberWorkouts.Workout.find()
This doesn't actually return anything. How do I debug from there?
If I replace that with this
EmberWorkouts.WorkoutsRoute = Ember.Route.extend
model: -> [{title: 'hi'}, {title: 'damn'}]
The view actually renders content.
How do I get the model to collect from Rails properly?
Ember Data's interface has changed a little with the current release:
You can clear out the store.js file entirely. Ember Data will automatically set up a data store for you using the REST Adapter (unless you tell it otherwise).
Use model: -> #store.find('workout') instead.
I tested this with your app and it works.
If you haven't read through the Ember Data Guide in the last week or two (it's changed a lot), I would spend a few minutes on it.
The fix for this error (as of ember-data 1.0.0.beta.6) for me was to make sure that the JSON returned from the server included an "id" field for each model, BUT not to explicitly declare the id when setting up the Ember DS.Model.
jbuilder template:
json.scans do
json.array! #scans do |scan|
json.id scan.id # This prop has to be there
json.name scan.name
end
end
Ember model:
EmberApp.Scan = DS.Model.extend(
// Don't include the id prop here
name: DS.attr("string")
)
Is there any way to add Sales Tax Item using QBFC?
Example:
Sales Tax A
4%
Sales Tax B
10%
I can add it easily from Quickbooks, but I need a way to add from external application using QBFC.
Any help will be greatly appreciated.
You can find a good example in the On Screen Reference.
At the top of the screen choose ItemSalesTaxAdd from the "Select Message" dropdown. From there click on the C# tab and you will see the following sample code:
//The following sample code is generated as an illustration of
//Creating requests and parsing responses ONLY
//This code is NOT intended to show best practices or ideal code
//Use at your most careful discretion
using System;
using System.Net;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using Interop.QBFC10;
namespace com.intuit.idn.samples
{
public class Sample
{
public void DoItemSalesTaxAdd()
{
bool sessionBegun = false;
bool connectionOpen = false;
QBSessionManager sessionManager = null;
try
{
//Create the session Manager object
sessionManager = new QBSessionManager();
//Create the message set request object to hold our request
IMsgSetRequest requestMsgSet = sessionManager.CreateMsgSetRequest("US",1,.0);
requestMsgSet.Attributes.OnError = ENRqOnError.roeContinue;
BuildItemSalesTaxAddRq(requestMsgSet);
//Connect to QuickBooks and begin a session
sessionManager.OpenConnection("","Sample Code from OSR");
connectionOpen = true;
sessionManager.BeginSession("", ENOpenMode.omDontCare);
sessionBegun = true;
//Send the request and get the response from QuickBooks
IMsgSetResponse responseMsgSet = sessionManager.DoRequests(requestMsgSet);
//End the session and close the connection to QuickBooks
sessionManager.EndSession();
sessionBegun = false;
sessionManager.CloseConnection();
connectionOpen = false;
WalkItemSalesTaxAddRs(responseMsgSet);
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error");
if (sessionBegun)
{
sessionManager.EndSession();
}
if (connectionOpen)
{
sessionManager.CloseConnection();
}
}
}
void BuildItemSalesTaxAddRq(IMsgSetRequest requestMsgSet)
{
IItemSalesTaxAdd ItemSalesTaxAddRq= requestMsgSet.AppendItemSalesTaxAddRq();
//Set field value for Name
ItemSalesTaxAddRq.Name.SetValue("ab");
//Set field value for BarCodeValue
ItemSalesTaxAddRq.BarCode.BarCodeValue.SetValue("ab");
//Set field value for AssignEvenIfUsed
ItemSalesTaxAddRq.BarCode.AssignEvenIfUsed.SetValue(true);
//Set field value for AllowOverride
ItemSalesTaxAddRq.BarCode.AllowOverride.SetValue(true);
//Set field value for IsActive
ItemSalesTaxAddRq.IsActive.SetValue(true);
//Set field value for ListID
ItemSalesTaxAddRq.ClassRef.ListID.SetValue("200000-1011023419");
//Set field value for FullName
ItemSalesTaxAddRq.ClassRef.FullName.SetValue("ab");
//Set field value for ItemDesc
ItemSalesTaxAddRq.ItemDesc.SetValue("ab");
//Set field value for TaxRate
ItemSalesTaxAddRq.TaxRate.SetValue(20.00);
//Set field value for ListID
ItemSalesTaxAddRq.TaxVendorRef.ListID.SetValue("200000-1011023419");
//Set field value for FullName
ItemSalesTaxAddRq.TaxVendorRef.FullName.SetValue("ab");
//Set field value for ExternalGUID
ItemSalesTaxAddRq.ExternalGUID.SetValue(Guid.NewGuid().ToString());
//Set field value for IncludeRetElementList
//May create more than one of these if needed
ItemSalesTaxAddRq.IncludeRetElementList.Add("ab");
}
void WalkItemSalesTaxAddRs(IMsgSetResponse responseMsgSet)
{
if (responseMsgSet == null) return;
IResponseList responseList = responseMsgSet.ResponseList;
if (responseList == null) return;
//if we sent only one request, there is only one response, we'll walk the list for this sample
for (int i=0; i<responseList.Count; i++)
{
IResponse response = responseList.GetAt(i);
//check the status code of the response, 0=ok, >0 is warning
if (response.StatusCode >= 0)
{
//the request-specific response is in the details, make sure we have some
if (response.Detail != null)
{
//make sure the response is the type we're expecting
ENResponseType responseType = (ENResponseType)response.Type.GetValue();
if (responseType == ENResponseType.rtItemSalesTaxAddRs)
{
//upcast to more specific type here, this is safe because we checked with response.Type check above
IItemSalesTaxRet ItemSalesTaxRet = (IItemSalesTaxRet)response.Detail;
WalkItemSalesTaxRet(ItemSalesTaxRet);
}
}
}
}
}
void WalkItemSalesTaxRet(IItemSalesTaxRet ItemSalesTaxRet)
{
if (ItemSalesTaxRet == null) return;
//Go through all the elements of IItemSalesTaxRet
//Get value of ListID
string ListID1 = (string)ItemSalesTaxRet.ListID.GetValue();
//Get value of TimeCreated
DateTime TimeCreated2 = (DateTime)ItemSalesTaxRet.TimeCreated.GetValue();
//Get value of TimeModified
DateTime TimeModified3 = (DateTime)ItemSalesTaxRet.TimeModified.GetValue();
//Get value of EditSequence
string EditSequence4 = (string)ItemSalesTaxRet.EditSequence.GetValue();
//Get value of Name
string Name5 = (string)ItemSalesTaxRet.Name.GetValue();
//Get value of BarCodeValue
if (ItemSalesTaxRet.BarCodeValue != null)
{
string BarCodeValue6 = (string)ItemSalesTaxRet.BarCodeValue.GetValue();
}
//Get value of IsActive
if (ItemSalesTaxRet.IsActive != null)
{
bool IsActive7 = (bool)ItemSalesTaxRet.IsActive.GetValue();
}
if (ItemSalesTaxRet.ClassRef != null)
{
//Get value of ListID
if (ItemSalesTaxRet.ClassRef.ListID != null)
{
string ListID8 = (string)ItemSalesTaxRet.ClassRef.ListID.GetValue();
}
//Get value of FullName
if (ItemSalesTaxRet.ClassRef.FullName != null)
{
string FullName9 = (string)ItemSalesTaxRet.ClassRef.FullName.GetValue();
}
}
//Get value of ItemDesc
if (ItemSalesTaxRet.ItemDesc != null)
{
string ItemDesc10 = (string)ItemSalesTaxRet.ItemDesc.GetValue();
}
//Get value of TaxRate
if (ItemSalesTaxRet.TaxRate != null)
{
double TaxRate11 = (double)ItemSalesTaxRet.TaxRate.GetValue();
}
if (ItemSalesTaxRet.TaxVendorRef != null)
{
//Get value of ListID
if (ItemSalesTaxRet.TaxVendorRef.ListID != null)
{
string ListID12 = (string)ItemSalesTaxRet.TaxVendorRef.ListID.GetValue();
}
//Get value of FullName
if (ItemSalesTaxRet.TaxVendorRef.FullName != null)
{
string FullName13 = (string)ItemSalesTaxRet.TaxVendorRef.FullName.GetValue();
}
}
//Get value of ExternalGUID
if (ItemSalesTaxRet.ExternalGUID != null)
{
string ExternalGUID14 = (string)ItemSalesTaxRet.ExternalGUID.GetValue();
}
if (ItemSalesTaxRet.DataExtRetList != null)
{
for (int i15 = 0; i15 < ItemSalesTaxRet.DataExtRetList.Count; i15++)
{
IDataExtRet DataExtRet = ItemSalesTaxRet.DataExtRetList.GetAt(i15);
//Get value of OwnerID
if (DataExtRet.OwnerID != null)
{
string OwnerID16 = (string)DataExtRet.OwnerID.GetValue();
}
//Get value of DataExtName
string DataExtName17 = (string)DataExtRet.DataExtName.GetValue();
//Get value of DataExtType
ENDataExtType DataExtType18 = (ENDataExtType)DataExtRet.DataExtType.GetValue();
//Get value of DataExtValue
string DataExtValue19 = (string)DataExtRet.DataExtValue.GetValue();
}
}
}
}
}
You can add each tax item as a line item. Make sure you set the invoice to a 0 tax, so tax is not calculated on top of tax.
You would have line item sales tax A and another line item sales tax B.
For example if we have these set of coordinates
"latitude": 48.858844300000001,
"longitude": 2.2943506,
How can we find out the city/country?
Another option:
Download the cities database from http://download.geonames.org/export/dump/
Add each city as a lat/long -> City mapping to a spatial index such as an R-Tree (some DBs also have the functionality)
Use nearest-neighbour search to find the closest city for any given point
Advantages:
Does not depend on an external server to be available
Very fast (easily does thousands of lookups per second)
Disadvantages:
Not automatically up to date
Requires extra code if you want to distinguish the case where the nearest city is dozens of miles away
May give weird results near the poles and the international date line (though there aren't any cities in those places anyway
The free Google Geocoding API provides this service via a HTTP REST API. Note, the API is usage and rate limited, but you can pay for unlimited access.
Try this link to see an example of the output (this is in json, output is also available in XML)
https://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true
You need geopy
pip install geopy
and then:
from geopy.geocoders import Nominatim
geolocator = Nominatim()
location = geolocator.reverse("48.8588443, 2.2943506")
print(location.address)
to get more information:
print (location.raw)
{'place_id': '24066644', 'osm_id': '2387784956', 'lat': '41.442115', 'lon': '-8.2939909', 'boundingbox': ['41.442015', '41.442215', '-8.2940909', '-8.2938909'], 'address': {'country': 'Portugal', 'suburb': 'Oliveira do Castelo', 'house_number': '99', 'city_district': 'Oliveira do Castelo', 'country_code': 'pt', 'city': 'Oliveira, São Paio e São Sebastião', 'state': 'Norte', 'state_district': 'Ave', 'pedestrian': 'Rua Doutor Avelino Germano', 'postcode': '4800-443', 'county': 'Guimarães'}, 'osm_type': 'node', 'display_name': '99, Rua Doutor Avelino Germano, Oliveira do Castelo, Oliveira, São Paio e São Sebastião, Guimarães, Braga, Ave, Norte, 4800-443, Portugal', 'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright'}
An Open Source alternative is Nominatim from Open Street Map.
All you have to do is set the variables in an URL and it returns the city/country of that location. Please check the following link for official documentation: Nominatim
I was searching for a similar functionality and I saw the data "http://download.geonames.org/export/dump/" shared on earlier reply (thank you for sharing, it is an excellent source), and implemented a service based on the cities1000.txt data.
You can see it running at
http://scatter-otl.rhcloud.com/location?lat=36&long=-78.9 (broken link)
Just change the latitude and longitude for your locations.
It is deployed on OpenShift (RedHat Platform). First call after a long idle period may take sometime, but usually performance is satisfactory.
Feel free to use this service as you like...
Also, you can find the project source at
https://github.com/turgos/Location.
I've used Geocoder, a good Python library that supports multiple providers, including Google, Geonames, and OpenStreetMaps, to mention just a few. I've tried using the GeoPy library, and it often gets timeouts. Developing your own code for GeoNames is not the best use of your time and you may end up getting unstable code. Geocoder is very simple to use in my experience, and has good enough documentation. Below is some sample code for looking up city by latitude and longitude, or finding latitude/longitude by city name.
import geocoder
g = geocoder.osm([53.5343609, -113.5065084], method='reverse')
print g.json['city'] # Prints Edmonton
g = geocoder.osm('Edmonton, Canada')
print g.json['lat'], g.json['lng'] # Prints 53.5343609, -113.5065084
I know this question is really old, but I have been working on the same issue and I found an extremely efficient and convenient package, reverse_geocoder, built by Ajay Thampi.
The code is available here. It based on a parallelised implementation of K-D trees which is extremely efficient for large amounts of points (it took me few seconds to get 100,000 points.
It is based on this database, already highlighted by #turgos.
If your task is to quickly find the country and city of a list of coordinates, this is a great tool.
I spent about an 30min trying to find a code example of how to do this in Javascript. I couldn't find a quick clear answer to the question you posted. So... I made my own. Hopefully people can use this without having to go digging into the API or staring at code they have no idea how to read. Ha if nothing else I can reference this post for my own stuff.. Nice question and thanks for the forum of discussion!
This is utilizing the Google API.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=<YOURGOOGLEKEY>&sensor=false&v=3&libraries=geometry"></script>
.
//CHECK IF BROWSER HAS HTML5 GEO LOCATION
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
//GET USER CURRENT LOCATION
var locCurrent = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
//CHECK IF THE USERS GEOLOCATION IS IN AUSTRALIA
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ 'latLng': locCurrent }, function (results, status) {
var locItemCount = results.length;
var locCountryNameCount = locItemCount - 1;
var locCountryName = results[locCountryNameCount].formatted_address;
if (locCountryName == "Australia") {
//SET COOKIE FOR GIVING
jQuery.cookie('locCountry', locCountryName, { expires: 30, path: '/' });
}
});
}
}
It really depends on what technology restrictions you have.
One way is to have a spatial database with the outline of the countries and cities you are interested in. By outline I mean that countries and cities are store as the spatial type polygon. Your set of coordinates can be converted to the spatial type point and queried against the polygons to get the country/city name where the point is located.
Here are some of the databases which support spatial type: SQL server 2008, MySQL, postGIS - an extension of postgreSQL and Oracle.
If you would like to use a service in stead of having your own database for this you can use Yahoo's GeoPlanet. For the service approach you might want to check out this answer on gis.stackexchange.com, which covers the availability of services for solving your problem.
You can use Google Geocoding API
Bellow is php function that returns Adress, City, State and Country
public function get_location($latitude='', $longitude='')
{
$geolocation = $latitude.','.$longitude;
$request = 'http://maps.googleapis.com/maps/api/geocode/json?latlng='.$geolocation.'&sensor=false';
$file_contents = file_get_contents($request);
$json_decode = json_decode($file_contents);
if(isset($json_decode->results[0])) {
$response = array();
foreach($json_decode->results[0]->address_components as $addressComponet) {
if(in_array('political', $addressComponet->types)) {
$response[] = $addressComponet->long_name;
}
}
if(isset($response[0])){ $first = $response[0]; } else { $first = 'null'; }
if(isset($response[1])){ $second = $response[1]; } else { $second = 'null'; }
if(isset($response[2])){ $third = $response[2]; } else { $third = 'null'; }
if(isset($response[3])){ $fourth = $response[3]; } else { $fourth = 'null'; }
if(isset($response[4])){ $fifth = $response[4]; } else { $fifth = 'null'; }
$loc['address']=''; $loc['city']=''; $loc['state']=''; $loc['country']='';
if( $first != 'null' && $second != 'null' && $third != 'null' && $fourth != 'null' && $fifth != 'null' ) {
$loc['address'] = $first;
$loc['city'] = $second;
$loc['state'] = $fourth;
$loc['country'] = $fifth;
}
else if ( $first != 'null' && $second != 'null' && $third != 'null' && $fourth != 'null' && $fifth == 'null' ) {
$loc['address'] = $first;
$loc['city'] = $second;
$loc['state'] = $third;
$loc['country'] = $fourth;
}
else if ( $first != 'null' && $second != 'null' && $third != 'null' && $fourth == 'null' && $fifth == 'null' ) {
$loc['city'] = $first;
$loc['state'] = $second;
$loc['country'] = $third;
}
else if ( $first != 'null' && $second != 'null' && $third == 'null' && $fourth == 'null' && $fifth == 'null' ) {
$loc['state'] = $first;
$loc['country'] = $second;
}
else if ( $first != 'null' && $second == 'null' && $third == 'null' && $fourth == 'null' && $fifth == 'null' ) {
$loc['country'] = $first;
}
}
return $loc;
}
If you are using Google's Places API, this is how you can get country and city from the place object using Javascript:
function getCityAndCountry(location) {
var components = {};
for(var i = 0; i < location.address_components.length; i++) {
components[location.address_components[i].types[0]] = location.address_components[i].long_name;
}
if(!components['country']) {
console.warn('Couldn\'t extract country');
return false;
}
if(components['locality']) {
return [components['locality'], components['country']];
} else if(components['administrative_area_level_1']) {
return [components['administrative_area_level_1'], components['country']];
} else {
console.warn('Couldn\'t extract city');
return false;
}
}
Loc2country is a Golang based tool that returns the ISO alpha-3 country code for given location coordinates (lat/lon). It responds in microseconds. It uses a geohash to country map.
The geohash data is generated using georaptor.
We use geohash at level 6 for this tool, i.e., boxes of size 1.2km x 600m.
Please check the below answer. It works for me
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position){
initialize(position.coords.latitude,position.coords.longitude);
});
}
function initialize(lat,lng) {
//directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
//directionsService = new google.maps.DirectionsService();
var latlng = new google.maps.LatLng(lat, lng);
//alert(latlng);
getLocation(latlng);
}
function getLocation(latlng){
var geocoder = new google.maps.Geocoder();
geocoder.geocode({'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[0]) {
var loc = getCountry(results);
alert("location is::"+loc);
}
}
});
}
function getCountry(results)
{
for (var i = 0; i < results[0].address_components.length; i++)
{
var shortname = results[0].address_components[i].short_name;
var longname = results[0].address_components[i].long_name;
var type = results[0].address_components[i].types;
if (type.indexOf("country") != -1)
{
if (!isNullOrWhitespace(shortname))
{
return shortname;
}
else
{
return longname;
}
}
}
}
function isNullOrWhitespace(text) {
if (text == null) {
return true;
}
return text.replace(/\s/gi, '').length < 1;
}
Minimize the amount of libraries.
Get a key to use the api at their website and just get the result in a http request:
curl -i -H "key: YOUR_KEY" -X GET https://api.latlong.dev/lookup?lat=38.7447913&long=-9.1625173
Update: My solution was not accurate enough, sometimes it returned incorrect country for coordinates right next to a border, or it would not return any country when the coordinates were at a seashore for example. At the end I went for paid MapBox reverse geocoding API. A request to URL https://api.mapbox.com/geocoding/v5/mapbox.places/<longitude>,<latitude>.json?access_token=<access token> returns geojson with location data - place name, region, country.
Original answer:
Download countries from https://www.naturalearthdata.com/downloads/ (I recommend using 1:10m for better accuracy), generate GeoJSON from it, and use some algorithm to detect if given coordinates are within a country polygon(s).
I used these steps to generate GeoJSON file:
Install Anaconda: https://www.anaconda.com/products/distribution
Install gdal: conda install -c conda-forge gdal (use elevated admin rights, more info on https://anaconda.org/conda-forge/gdal)
Download 1:10m countries form https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_0_countries.zip, extract it.
Set environment variable: setx PROJ_LIB C:\ProgramData\Anaconda3\Library\share\proj\
Run command C:\ProgramData\Anaconda3\Library\bin\ogr2ogr.exe -f GeoJSON -t_srs crs:84 data.geo.json ne_10m_admin_0_countries.shp
This will generate data.geo.json which has around 24MB. You can alternatively download it here.
C#:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace SmartGuide.Core.Services.CountryLocators
{
public static class CountryLocator
{
private static readonly Lazy<List<CountryPolygons>> _countryPolygonsByCountryName = new(() =>
{
var dataGeoJsonFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data.geo.json");
var stream = new FileStream(dataGeoJsonFileName, FileMode.Open, FileAccess.Read);
var geoJson = _Deserialize<Root>(stream);
var countryPolygonsByCountryName = geoJson.Features.Select(
feature => new CountryPolygons
{
CountryName = feature.Properties.Name,
Polygons =
feature.Geometry.Type switch
{
"Polygon" => new List<List<GpsCoordinate>>(
new[]
{
feature.Geometry.Coordinates[0]
.Select(x => new GpsCoordinate(
Convert.ToDouble(x[1]),
Convert.ToDouble(x[0])
)
).ToList()
}
),
"MultiPolygon" => feature.Geometry.Coordinates.Select(
polygon => polygon[0].Select(x =>
new GpsCoordinate(
Convert.ToDouble(((JArray) x)[1]),
Convert.ToDouble(((JArray) x)[0])
)
).ToList()
)
.ToList(),
_ => throw new NotImplementedException($"Unknown geometry type {feature.Geometry.Type}")
}
}
).ToList();
return countryPolygonsByCountryName;
});
public static string GetCountryName(GpsCoordinate coordinate)
{
var country = _countryPolygonsByCountryName.Value.FirstOrDefault(country =>
country.Polygons.Any(polygon => _IsPointInPolygon(polygon, coordinate)));
return country?.CountryName;
}
// taken from https://stackoverflow.com/a/7739297/379279
private static bool _IsPointInPolygon(IReadOnlyList<GpsCoordinate> polygon, GpsCoordinate point)
{
int i, j;
bool c = false;
for (i = 0, j = polygon.Count - 1; i < polygon.Count; j = i++)
{
if ((((polygon[i].Latitude <= point.Latitude) && (point.Latitude < polygon[j].Latitude))
|| ((polygon[j].Latitude <= point.Latitude) && (point.Latitude < polygon[i].Latitude)))
&& (point.Longitude < (polygon[j].Longitude - polygon[i].Longitude) * (point.Latitude - polygon[i].Latitude)
/ (polygon[j].Latitude - polygon[i].Latitude) + polygon[i].Longitude))
{
c = !c;
}
}
return c;
}
private class CountryPolygons
{
public string CountryName { get; set; }
public List<List<GpsCoordinate>> Polygons { get; set; }
}
public static TResult _Deserialize<TResult>(Stream stream)
{
var serializer = new JsonSerializer();
using var sr = new StreamReader(stream);
using var jsonTextReader = new JsonTextReader(sr);
return serializer.Deserialize<TResult>(jsonTextReader);
}
public readonly struct GpsCoordinate
{
public GpsCoordinate(
double latitude,
double longitude
)
{
Latitude = latitude;
Longitude = longitude;
}
public double Latitude { get; }
public double Longitude { get; }
}
}
}
// Generated by https://json2csharp.com/ (with Use Pascal Case) from data.geo.json
public class Feature
{
public string Type { get; set; }
public string Id { get; set; }
public Properties Properties { get; set; }
public Geometry Geometry { get; set; }
}
public class Geometry
{
public string Type { get; set; }
public List<List<List<object>>> Coordinates { get; set; }
}
public class Properties
{
public string Name { get; set; }
}
public class Root
{
public string Type { get; set; }
public List<Feature> Features { get; set; }
}
Tests:
[TestFixture]
public class when_locating_country
{
[TestCase(49.2231391, 17.8545076, "Czechia", TestName = "1 Vizovice, Czech Republic")]
[TestCase(2.9263126, -75.2891733, "Colombia", TestName = "2 Neiva, Colombia")]
[TestCase(12, -70, "Venezuela", TestName = "3 Paraguana, Venezuela")]
[TestCase(-5.0721976, 39.0993457, "Tanzania", TestName = "4 Tanga, Tanzania")]
[TestCase(42.9830241, 47.5048716, "Russia", TestName = "5 Makhachkala, Russia")]
public void country_is_located_correctly(double latitude, double longitude, string expectedCountryName)
{
var countryName = CountryLocator.GetCountryName(new CountryLocator.GpsCoordinate(latitude, longitude));
countryName.ShouldBe(expectedCountryName);
}
}
JS: you can use https://github.com/vkurchatkin/which-country and replace the not so accurate https://github.com/vkurchatkin/which-country/blob/master/lib/data.geo.json by the generated one. I didn't test it though.
You can do it with: https://www.weatherapi.com/ its FREE.
My demo is in React and step by step, but you can do it in any way you want, the key is this Weather API, that accepts LON and LAT as a string to produce city and weather info -> https://api.weatherapi.com/v1/forecast.json?key=YOUR_KEY&q=LATITUDE,LONGITUDE&days=1&aqi=no&alerts=n
Note: you will to generate YOUR OWN KEY, by signing up
You will need 3 states for this:
const [latitude, setLatitude] = useState("");
const [longitude, setLongitude] = useState("");
const [city, setCity] = useState("");
First: Request access to 'location' from user (this will have a POP-UP), by using this code and set state to Latitude and Longitude.
useEffect(() => {
function getPosition() {
const successCallback = (position) => {
console.log(position);
setLatitude(position.coords.latitude);
setLongitude(position.coords.longitude);
};
const errorCallback = (error) => {
console.log(error);
};
navigator.geolocation.getCurrentPosition(successCallback, errorCallback);
}
getPosition();
}, []);
Second use https://www.weatherapi.com/ API to get City and other intel, based on Lat and Lon
API looks like this: https://api.weatherapi.com/v1/forecast.json?key=3e5e13fac8354c818de152831211305&q=53.3498053,-6.2603097&days=1&aqi=no&alerts=n
API with explanation: https://api.weatherapi.com/v1/forecast.json?key=3e5e13fac8354c818de152831211305&q=LATITUDE,LONGITUDE&days=1&aqi=no&alerts=n
Now call this API with latitude and longitude to get location data, including city. I am using useEffect as a trigger, so as soon as I get info on Latitude I call the api using axios and set City state to what ever comes out of the api object.
useEffect(() => {
async function getWeather() {
let res = await axios.get(
`https://api.weatherapi.com/v1/forecast.json?key=3e5e13fac8354c818de152831211305&q=${latitude},${longitude}&days=1&aqi=no&alerts=no`
);
console.log(res.data);
setCity(res.data.location.name);
}
getWeather();
}, [latitude, longitude]);
RESULT from API:
"location": {
"name": "Dublin",
"region": "Dublin",
"country": "Ireland",
"lat": 53.35,
"lon": -6.26,
"tz_id": "Europe/Dublin",
"localtime_epoch": 1673737376,
"localtime": "2023-01-14 23:02"
},
Here is video to my youtube channel, where you can see a demo of this: https://youtu.be/gxcG8V3Fpbk