2011-09-27 23 views
13

हमें Google मानचित्र पर अक्षांश/लंबे मूल्यों और बहुभुज के लिए पॉइंट-इन-पॉलीगॉन के लिए एक त्वरित और काफी सटीक विधि का पता लगाने की आवश्यकता है। कुछ शोध के बाद - mysql ज्यामितीय एक्सटेंशन के बारे में कुछ पोस्ट में आया, और लागू किया है कि बहुत -रे-कास्टिंग एल्गोरिदम का MySQL कार्यान्वयन?

SELECT id, Contains(PolyFromText('POLYGON(".$polygonpath.")') , PointFromText(concat(\"POINT(\", latitude, \" \", longitude, \")\"))) AS 
      CONTAINS 
FROM tbl_points 

कि हालांकि अंक :(की एक बड़ी संख्या के ऊपर

बनाया कुछ और करने के बाद बहुभुज के साथ काम नहीं किया शोध - रे-कास्टिंग एल्गोरिदम नामक एक मानक एल्गोरिदम में आया लेकिन माईएसक्यूएल में इसके लिए एक क्वेरी विकसित करने से पहले, अगर कोई पहले से ही हो रहा था या एक उपयोगी लिंक में आया तो यह मेरी संभावनाएं लेना चाहता था जो दिखाता है कि एल्गोरिदम को कैसे कार्यान्वित किया जाए MySQL/SQL-Server।

तो, इसे छोटा प्रश्न पूछना है:

क्या कोई भी रे कास्टिंग एल्गोरिदम के MySQL/SQL-server कार्यान्वयन प्रदान कर सकता है?

अतिरिक्त विवरण:

  • बहुभुज अवतल, उत्तल या जटिल के दोनों कर रहे हैं।
  • 100% सटीकता से त्वरित निष्पादन को लक्षित करना। एक यूडीएफ
    लिखने के लिए

    लिंक यहाँ एक MySQL जीआईएस के लिए sourcecode है:

+4

जब मैंने एक साल पहले माइस्क्लुएल में भू-स्थानिक विस्तार को देखा, तो वे बीटा गुणवत्ता सर्वश्रेष्ठ थे। मैं अपने भौगोलिक डेटाबेस के लिए PostgreSQL का उपयोग कर समाप्त हो गया।मैंने डेटाबेस में रे कास्टिंग को लागू करने की कोशिश करने वाले किसी के बारे में कभी नहीं सुना है, हालांकि ... –

+0

@EricJ। - आपकी प्रतिक्रिया के लिए धन्यवाद। काश मैं इस समस्या के लिए पोस्टजीआईएस का उपयोग कर सकता हूं .. लेकिन ऐसा नहीं कर सकता क्योंकि यह एक विशाल प्रणाली का केवल एक छोटा सा हिस्सा है। :( – zarun

+0

MySQL में cos/sin/tan फ़ंक्शन हैं, क्या इससे आपकी मदद मिलती है? लिंक: http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html – Johan

उत्तर

18

निम्नलिखित समारोह (Raycasting एल्गोरिथ्म के MySQL संस्करण) मेरी दुनिया हिल:

CREATE FUNCTION myWithin(p POINT, poly POLYGON) RETURNS INT(1) DETERMINISTIC 
BEGIN 
DECLARE n INT DEFAULT 0; 
DECLARE pX DECIMAL(9,6); 
DECLARE pY DECIMAL(9,6); 
DECLARE ls LINESTRING; 
DECLARE poly1 POINT; 
DECLARE poly1X DECIMAL(9,6); 
DECLARE poly1Y DECIMAL(9,6); 
DECLARE poly2 POINT; 
DECLARE poly2X DECIMAL(9,6); 
DECLARE poly2Y DECIMAL(9,6); 
DECLARE i INT DEFAULT 0; 
DECLARE result INT(1) DEFAULT 0; 
SET pX = X(p); 
SET pY = Y(p); 
SET ls = ExteriorRing(poly); 
SET poly2 = EndPoint(ls); 
SET poly2X = X(poly2); 
SET poly2Y = Y(poly2); 
SET n = NumPoints(ls); 
WHILE i<n DO 
SET poly1 = PointN(ls, (i+1)); 
SET poly1X = X(poly1); 
SET poly1Y = Y(poly1); 
IF ((((poly1X <= pX) && (pX < poly2X)) || ((poly2X <= pX) && (pX < poly1X))) && (pY > (poly2Y - poly1Y) * (pX - poly1X)/(poly2X - poly1X) + poly1Y)) THEN 
SET result = !result; 
END IF; 
SET poly2X = poly1X; 
SET poly2Y = poly1Y; 
SET i = i + 1; 
END WHILE; 
RETURN result; 
End; 

जोड़े

DELIMITER ;; 
आवश्यकतानुसार कार्य से पहले

। समारोह के लिए उपयोग है:

SELECT myWithin(point, polygon) as result; 

जहां

point = Point(lat,lng) 
polygon = Polygon(lat1 lng1, lat2 lng2, lat3 lng3, .... latn lngn, lat1 lng1) 

कृपया ध्यान दें कि बहुभुज को बंद करना पड़ा (सामान्य रूप से यह आप एक मानक kml या googlemap डेटा पुन: प्राप्त कर रहे हैं तो बंद कर दिया लेकिन सिर्फ है चाहिए सुनिश्चित करें कि यह है - lat1 lng1 सेट अंत में दोहराया जाता है)

मैं ज्यामितीय क्षेत्रों के रूप में मेरे डेटाबेस में अंक और बहुभुज नहीं था ध्यान दें, तो मैं कुछ ऐसा करना ही था:

+०१२३५१६४१०६
Select myWithin(PointFromText(concat("POINT(", latitude, " ", longitude, ")")),PolyFromText('POLYGON((lat1 lng1, ..... latn lngn, lat1 lng1))')) as result 

मुझे उम्मीद है कि यह किसी की मदद कर सकता है।

+0

+1 अपना परिणामी कोड साझा करने के लिए। – Johan

5

मुझे लगता है कि सी या डेल्फी या जो कुछ भी उच्च स्तर उपकरण आप उपयोग में रे कास्टिंग एल्गोरिथ्म को लागू करता है एक कस्टम यूडीएफ लिखते थे क्रियान्वयन जो किसी क्षेत्र पर बिंदु दिखता है (यह देखने के लिए टेम्पलेट के रूप में उपयोग करें कि MySQL में स्थानिक डेटाटाइप के साथ कैसे बातचीत करें)।
http://www.lenzg.net/archives/220-New-UDF-for-MySQL-5.1-provides-GIS-functions-distance_sphere-and-distance_spheroid.html

MySQL मैनुअल से:
http://dev.mysql.com/doc/refman/5.0/en/adding-functions.html

यूडीएफ एमएस विजुअल C++
http://rpbouman.blogspot.com/2007/09/creating-mysql-udfs-with-microsoft.html

डेल्फी में यूडीएफ ट्यूटोरियल के लिए ट्यूटोरियल:
Creating a UDF for MySQL in Delphi

स्रोत-कोड के बारे में रे कास्टिंग एल्गोरिदम
छद्म कोड: drDobbs में http://rosettacode.org/wiki/Ray-casting_algorithm
अनुच्छेद (लेख के शीर्ष पर कोड के लिए लिंक पर ध्यान दें): http://drdobbs.com/cpp/184409586
डेल्फी (वास्तव में FreePascal): http://www.cabiatl.com/mricro/raycast/

+0

+1 बस ध्यान रखें कि कस्टम MySQL – Cez

+0

को अपग्रेड करते समय यूडीएफ टूट सकता है धन्यवाद! बहुत सारे उपयोगी लिंक हैं। उनमें से प्रत्येक के माध्यम से जा रहे हैं। इसके अलावा, जब मैं इस अधिसूचना प्रणाली में आया तो समस्या में फंस गया था, जो कि कुछ महत्वपूर्ण होने पर उपयोगकर्ताओं को सीमा में सूचित करना चाहिए अंदर पोस्ट किया गया। तो - उपयोगकर्ता (अंक), घटना (अंक) और सीमा (बहुभुज) .. मुझे लगता है कि इस तरह की सीमा की जानकारी को एक समारोह में पास करने में धीमा हो जाएगा और फिर जांच करें कि घटना बिंदु भीतर है या नहीं सीमा - फिर एक समय में सभी वैध उपयोगकर्ताओं को इस तरह की वैध सीमा के भीतर जांचें और उन्हें सूचित करें; ( – zarun

+1

@zarun चाल यह सुनिश्चित करने के लिए है कि आप इंडेक्स का उपयोग कर सकें। इंडेक्स आपको 99.99% खोज स्थान को खत्म करने की अनुमति देता है। चीज़ें अप। – Johan

1

मैं बहुभुज की एक तालिका पर उपर्युक्त mywithin संग्रहीत प्रक्रिया का उपयोग करना चाहता था, इसलिए बस ऐसा करने के लिए आदेश हैं।

ogr2ogr का उपयोग कर के रूप में इस प्रकार है

ogr2ogr -f "mysql" MYSQL:"mydbname,host=localhost,user=root,password=mypassword,port=3306" -nln "mytablename" -a_srs "EPSG:4326" /path/to/shapefile.shp 

आप तो अपनी मेज prefilter को MBRwithin उपयोग कर सकते हैं mysql में कोई शेपफ़ाइल बहुभुज युक्त आयात और के रूप में

DROP TEMPORARY TABLE IF EXISTS POSSIBLE_POLYS; 
CREATE TEMPORARY TABLE POSSIBLE_POLYS(OGR_FID INT,SHAPE POLYGON); 
INSERT INTO POSSIBLE_POLYS (OGR_FID, SHAPE) SELECT mytablename.OGR_FID,mytablename.SHAPE FROM mytablename WHERE MBRwithin(@testpoint,mytablename.SHAPE); 

DROP TEMPORARY TABLE IF EXISTS DEFINITE_POLY; 
CREATE TEMPORARY TABLE DEFINITE_POLY(OGR_FID INT,SHAPE POLYGON); 
INSERT INTO DEFINITE_POLY (OGR_FID, SHAPE) SELECT POSSIBLE_POLYS.OGR_FID,POSSIBLE_POLYS.SHAPE FROM POSSIBLE_POLYS WHERE mywithin(@testpoint,POSSIBLE_POLYS.SHAPE); 

इस प्रकार समाप्त करने के लिए mywithin जहां @testpoint बनाई गई है के बाद , उदाहरण के लिए,

SET @longitude=120; 
SET @latitude=-30; 
SET @testpoint =(PointFromText(concat("POINT(", @longitude, " ", @latitude, ")"))); 
2

बस मामले में, एक MySQL समारोह जो एक इनपुट के रूप MULTIPOLYGON स्वीकार करता है: http://forums.mysql.com/read.php?23,286574,286574

DELIMITER $$ 

CREATE DEFINER=`root`@`localhost` FUNCTION `GISWithin`(pt POINT, mp MULTIPOLYGON) RETURNS int(1) 
    DETERMINISTIC 
BEGIN 

DECLARE str, xy TEXT; 
DECLARE x, y, p1x, p1y, p2x, p2y, m, xinters DECIMAL(16, 13) DEFAULT 0; 
DECLARE counter INT DEFAULT 0; 
DECLARE p, pb, pe INT DEFAULT 0; 

SELECT MBRWithin(pt, mp) INTO p; 

IF p != 1 OR ISNULL(p) THEN 
    RETURN p; 
END IF; 

SELECT X(pt), Y(pt), ASTEXT(mp) INTO x, y, str; 
SET str = REPLACE(str, 'POLYGON((',''); 
SET str = REPLACE(str, '))', ''); 
SET str = CONCAT(str, ','); 

SET pb = 1; 
SET pe = LOCATE(',', str); 
SET xy = SUBSTRING(str, pb, pe - pb); 
SET p = INSTR(xy, ' '); 
SET p1x = SUBSTRING(xy, 1, p - 1); 
SET p1y = SUBSTRING(xy, p + 1); 
SET str = CONCAT(str, xy, ','); 

WHILE pe > 0 DO 
    SET xy = SUBSTRING(str, pb, pe - pb); 
    SET p = INSTR(xy, ' '); 
    SET p2x = SUBSTRING(xy, 1, p - 1); 
    SET p2y = SUBSTRING(xy, p + 1); 

    IF p1y < p2y THEN SET m = p1y; ELSE SET m = p2y; END IF; 

    IF y > m THEN 
     IF p1y > p2y THEN SET m = p1y; ELSE SET m = p2y; END IF; 
     IF y <= m THEN 
      IF p1x > p2x THEN SET m = p1x; ELSE SET m = p2x; END IF; 
      IF x <= m THEN 
       IF p1y != p2y THEN 
        SET xinters = (y - p1y) * (p2x - p1x)/(p2y - p1y) + p1x; 
       END IF; 
       IF p1x = p2x OR x <= xinters THEN 
        SET counter = counter + 1; 
       END IF; 
      END IF; 
     END IF; 
    END IF; 

    SET p1x = p2x; 
    SET p1y = p2y; 
    SET pb = pe + 1; 
    SET pe = LOCATE(',', str, pb); 
END WHILE; 

RETURN counter % 2; 

END 
1

अब यह MySQL5.6.1 और इसके बाद के संस्करण के रूप में एक स्थानिक एक्सटेंशन है। function_st-contains पर Docs पर देखें।

+0

लिंक के साथ बस एक पंक्ति StackOverflow पर एक उत्तर नहीं है। कृपया इस पोस्ट में लिंक से जानकारी - जैसे सारांश और कोड उदाहरण शामिल करें। –

1

पॉलीगॉन के भीतर लेट/लम्बे समय के लिए ज़ारुन फ़ंक्शन के जवाब में।

मेरे पास एक संपत्ति तालिका थी जिसमें लेट/लंबी जानकारी थी। तो मुझे उन अभिलेखों को प्राप्त करना पड़ा जिनके लेट/लांग बहुभुज लैट/लम्बे (जो मुझे Google एपीआई से मिला) के भीतर स्थित है। सबसे पहले मैं ज़रुण समारोह का उपयोग करने के लिए गूंगा था। तो यहां इसके लिए समाधान पूछताछ है।

  • तालिका: गुण
  • फील्ड्स: आईडी, अक्षांश, देशांतर, बेड आदि ...
  • क्वेरी:
SELECT id 
FROM properties 
WHERE myWithin(
    PointFromText(concat("POINT(", latitude, " ", longitude, ")")), 
    PolyFromText('POLYGON((37.628134 -77.458334,37.629867 -77.449021,37.62324 -77.445416,37.622424 -77.457819,37.628134 -77.458334))') 
) = 1 limit 0,50; 

आशा है कि यह समय की बचत करेंगे मेरे जैसे डंब्स के लिए;)

+0

धन्यवाद! इसका उपयोग करने के लिए पोस्ट करने के लिए मेरे पास नहीं हुआ! :-D – zarun

1

यहां एक संस्करण है जो मल्टीपोलिगन्स के साथ काम करता है (ज़ारुन का एक अनुकूलन जो केवल पॉलीगोन के लिए काम करता है)।

CREATE FUNCTION GISWithin(p POINT, multipoly MULTIPOLYGON) RETURNS INT(1) DETERMINISTIC 
BEGIN 
DECLARE n,i,m,x INT DEFAULT 0; 
DECLARE pX,pY,poly1X,poly1Y,poly2X,poly2Y DECIMAL(13,10); 
DECLARE ls LINESTRING; 
DECLARE poly MULTIPOLYGON; 
DECLARE poly1,poly2 POINT; 
DECLARE result INT(1) DEFAULT 0; 
SET pX = X(p); 
SET pY = Y(p); 
SET m = NumGeometries(multipoly); 
WHILE x<m DO 
SET poly = GeometryN(multipoly,x); 
SET ls = ExteriorRing(poly); 
SET poly2 = EndPoint(ls); 
SET poly2X = X(poly2); 
SET poly2Y = Y(poly2); 
SET n = NumPoints(ls); 
WHILE i<n DO 
SET poly1 = PointN(ls, (i+1)); 
SET poly1X = X(poly1); 
SET poly1Y = Y(poly1); 
IF ((((poly1X <= pX) && (pX < poly2X)) || ((poly2X <= pX) && (pX < poly1X))) && (pY > (poly2Y - poly1Y) * (pX - poly1X)/(poly2X - poly1X) + poly1Y)) THEN 
SET result = !result; 
END IF; 
SET poly2X = poly1X; 
SET poly2Y = poly1Y; 
SET i = i + 1; 
END WHILE; 
SET x = x + 1; 
END WHILE; 
RETURN result; 
End; 
संबंधित मुद्दे