Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Province from coordinate #361

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@
"editor.defaultFormatter": "esbenp.prettier-vscode",
"vitest.enable": true,
"testing.alwaysRevealTestOnStateChange": true,
"testing.automaticallyOpenPeekView": "never"
"testing.automaticallyOpenPeekView": "never",
"[json]": {
"editor.defaultFormatter": "vscode.json-language-features"
}
}
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
- [Get the Remaining Time of the Date](#get-the-remaining-time-of-the-date)
- [Validate and find information of phone number](#validate-and-find-information-of-phone-number).
- [Find capital city by province name ](#find-capital-city-by-province-name)

- [Find province from coordinate ](#find-province-from-coordinate)
## Getting started

There are two main ways to get PersianTools.js in your JavaScript project:
Expand Down Expand Up @@ -557,6 +557,28 @@ findCapitalByProvince("آذربایجان شرقی"); // تبریز
// this throw an error string 'no province found'
findCapitalByProvince("دبی");
```
### Find province from coordinate

**Usage**

> Find the province from a given coordinate point. If it cannot find anything, it will throw an error.

```javascript
import { findProvinceFromCoordinate } from "@persian-tools/persian-tools";

// Find province for a given coordinate point
const point = { latitude: 35.6892, longitude: 51.3890 };

const province = findProvinceFromCoordinate(point);

province.fa; // "تهران"
province.en; // "Tehran"

// shorthand syntax using destructuring
const {fa , en} = findProvinceFromCoordinate(point);

```


### Todo

Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,6 @@ export { default as remainingTime } from "./modules/remainingTime";
//Find capital city by state name

export { default as findCapitalByProvince } from "./modules/findCapitalByProvince";

//Find Province from Coordinates
export { default as findProvinceFromCoordinate } from "./modules/findProvinceFromCoordinate";
75 changes: 75 additions & 0 deletions src/modules/findProvinceFromCoordinate/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { GeoJSONData } from "./IRGeoJSON";

interface Point {
longitude: number;
latitude: number;
}

interface GeoJSONFeature {
properties: Record<string, string | undefined>;
geometry: {
type: string;
coordinates: object; // This represents MultiPolygon coordinates
};
}

interface Province {
fa: string;
en: string;
}

const provinces = GeoJSONData;

function pointInPolygon(polygon: number[][], point: Point): boolean {
let isInside = false;
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
const xi = polygon[i][0];
const yi = polygon[i][1];
const xj = polygon[j][0];
const yj = polygon[j][1];

const { longitude: x, latitude: y } = point;

if (yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi) {
isInside = !isInside;
}
}
return isInside;
}

/**
* Find the province from a given coordinate point.
* @param pointToCheck The coordinate point to check.
* @returns The province information.
* @throws {Error} If the province cannot be found based on the provided coordinates.
* @example
* const point: Point = { latitude: 35.6892, longitude: 51.3890 };
* const province = findProvinceFromCoordinate(point);
* console.log(province.fa); // "تهران"
* console.log(province.en); // "Tehran"
* @example
* const {fa , en} = findProvinceFromCoordinate(point);
*/
export const findProvinceFromCoordinate = (pointToCheck: Point): Province => {
let foundProvince: GeoJSONFeature | undefined;
for (let index = 0; index < provinces.features.length; index++) {
const province = provinces.features[index];
const provinceGeometryCoords = province.geometry.coordinates[0][0];
const isInsideProvince = pointInPolygon(provinceGeometryCoords, pointToCheck);
if (isInsideProvince) {
foundProvince = province;
break;
}
}
if (foundProvince) {
const normalizedProvinceObject: Province = {
fa: foundProvince.properties.name || "",
en: foundProvince.properties["name:en"] || "",
};
return normalizedProvinceObject;
} else {
throw new Error("Could not find province based on provided coordinates !");
}
};

export default findProvinceFromCoordinate;
1 change: 1 addition & 0 deletions src/modules/findProvinceFromCoordinate/irGeoJSON.ts

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions test/findProvinceFromCoordinate.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { findProvinceFromCoordinate } from "../src";
import { it, expect } from "vitest";

it("should throw an error when there isn't any coordinate", () => {
expect(() => {
findProvinceFromCoordinate({
longitude: 1,
latitude: 2
});
}).toThrow();
});

it("Should return the correct province for a given coordinate", () => {

const pointToCheck = { longitude: 51.38897, latitude: 35.6892 };

const {fa , en } = findProvinceFromCoordinate(pointToCheck);

expect(fa).toBe('تهران');
expect(en).toBe('Tehran');
});

it("Should return the correct province for a coordinate in Isfahan", () => {

const pointToCheck = { longitude: 51.6660, latitude: 32.6546 };

const {fa , en } = findProvinceFromCoordinate(pointToCheck);

expect(fa).toBe('اصفهان');
expect(en).toBe('Esfahan');
});