আমাকে প্রথমবারের মতো এসকিউএল সার্ভারে স্থানিক ডেটা নিয়ে খেলছি (তাই আপনি সম্ভবত এটি প্রথম অংশটি জানেন) তবে এসকিউএল সার্ভার (xyz) স্থানাঙ্ককে সত্য হিসাবে চিকিত্সা করছে না তা বুঝতে আমাকে বেশ সময় লাগল 3 ডি মান, এটি তাদের (অক্ষাংশ দ্রাঘিমাংশ) হিসাবে একটি alচ্ছিক "উচ্চতা" মান, জেড হিসাবে বিবেচনা করে যা বৈধতা এবং অন্যান্য ফাংশন দ্বারা উপেক্ষা করা হয়।
প্রমান:
select geography::STGeomFromText('LINESTRING (0 0 1, 0 1 2, 0 -1 3)', 4326)
.IsValidDetailed()
24413: Not valid because of two overlapping edges in curve (1).
আপনার প্রথম উদাহরণটি আমার কাছে অদ্ভুত বলে মনে হয়েছিল কারণ (0 0 1), (0 1 2), এবং (0 -1 3) 3 ডি স্পেসে কোলাইনারি নয় (আমি একজন গণিতবিদ, তাই আমি এই পদগুলিতে ভাবছিলাম)। IsValidDetailed
(এবং MakeValid
) এগুলি (0 0), (0 1) এবং (0, -1) হিসাবে আচরণ করছে, যা একটি ওভারল্যাপিং লাইন তৈরি করে।
এটি প্রমাণ করতে, কেবল এক্স এবং জেড অদলবদল করুন এবং এটি বৈধতা দেয়:
select geography::STGeomFromText('LINESTRING (1 0 0, 2 1 0, 3 -1 0)', 4326)
.IsValidDetailed()
24400: Valid
এটি গাণিতিক 3 ডি স্পেসের পয়েন্টের পরিবর্তে আমাদের পৃথিবীর পৃষ্ঠে চিহ্নিত অঞ্চল বা পথ হিসাবে যদি মনে হয় তবে এটি প্রকৃত অর্থে আসে।
আপনার সমস্যার দ্বিতীয় অংশটি হ'ল জেড (এবং এম) পয়েন্টের মানগুলি এসকিউএল দ্বারা ফাংশনগুলির মাধ্যমে সংরক্ষণ করা হয় না :
জেড-স্থানাঙ্কগুলি লাইব্রেরি দ্বারা তৈরি কোনও গণনায় ব্যবহৃত হয় না এবং কোনও লাইব্রেরি গণনার মধ্য দিয়ে বহন করা হয় না।
এটি দুর্ভাগ্যক্রমে নকশা দ্বারা। এটি মাইক্রোসফ্টকে 2010 সালে জানানো হয়েছিল, অনুরোধটি "উইল্ট ফিক্স" হিসাবে বন্ধ করা হয়েছিল। আপনি সেই আলোচনাটিকে প্রাসঙ্গিক মনে করতে পারেন, তাদের যুক্তিটি হ'ল:
জেড এবং এম নির্ধারণ করা অস্পষ্ট, কারণ মেকভালিড স্থানিক উপাদানগুলিকে বিভক্ত করে এবং মার্জ করে। পয়েন্টগুলি প্রায়শই এই প্রক্রিয়া চলাকালীন তৈরি, সরানো বা সরানো হয়। অতএব মেকভালিড (এবং অন্যান্য নির্মাণগুলি) জেড এবং এম এর মানকে হ্রাস করে।
উদাহরণ স্বরূপ:
DECLARE @a geometry = geometry::Parse('POINT(0 0 2 2)');
DECLARE @b geometry = geometry::Parse('POINT(0 0 1 1)');
SELECT @a.STUnion(@b).AsTextZM()
মান Z এবং এম বিন্দু (0 0) এর জন্য অস্পষ্ট। আমরা অর্ধ-সঠিক ফলাফলটি না ফেরার পরিবর্তে জেড এবং এমকে পুরোপুরি বাদ দেওয়ার সিদ্ধান্ত নিয়েছি।
আপনি ঠিক কীভাবে জানেন তা যদি আপনি পরে এগুলিকে নিয়োগ করতে পারেন। বিকল্পভাবে আপনি ইনপুটটিতে বৈধ হওয়ার জন্য আপনার জিনিসগুলি যেভাবে উত্পন্ন করেন তা পরিবর্তন করতে পারেন, বা আপনার অবজেক্টের দুটি সংস্করণ রাখতে পারেন, এটি বৈধ এবং অন্যটি যা আপনার সমস্ত বৈশিষ্ট্য সংরক্ষণ করে। যদি আপনি আপনার দৃশ্যের আরও ভালভাবে ব্যাখ্যা করেন এবং আপনি কী কী জিনিসগুলি নিয়ে করেন সম্ভবত আমরা আপনাকে অতিরিক্ত কাজের পরিমাণ দিতে সক্ষম হতে পারি।
তদতিরিক্ত, আপনি ইতিমধ্যে দেখেছেন, MakeValid
অন্যান্য অপ্রত্যাশিত কাজগুলিও করতে পারে , যেমন পয়েন্টের ক্রম পরিবর্তন করা, একটি মাল্টলাইনস্ট্রিং ফিরিয়ে দিতে, বা এমনকি কোনও পয়েন্ট অবজেক্ট ফেরত দেওয়া।
আমি যে ধারণাটি পেয়েছি সেগুলি হ'ল এগুলি পরিবর্তে একটি মাল্টিপোয়েন্ট অবজেক্ট হিসাবে সংরক্ষণ করা :
সমস্যাটি যখন তখন আপনার লাইনস্ট্রিংটি দুটি পয়েন্টের মধ্যে লাইনের একটি ধারাবাহিক বিভাগকে পূর্বে রেখার দ্বারা চিহ্নিত করে ret সংজ্ঞা অনুসারে, আপনি যদি বিদ্যমান পয়েন্টগুলি প্রত্যাহার করে থাকেন তবে লাইনস্ট্রিং আর সহজ জ্যামিতি নয় যা এই পয়েন্টসটি উপস্থাপন করতে পারে এবং মেকাভালিড () আপনাকে পরিবর্তে একটি মাল্টিলিনেস্ট্রিং দেবে (এবং আপনার জেড / এম মান হারাবে)।
দুর্ভাগ্যক্রমে, আপনি যদি জিপিএস ডেটা বা এর সাথে কাজ করে থাকেন তবে সম্ভবত এই পথটির কোনও সময়ে আপনি আপনার পথটি পিছনে ফেলেছেন সম্ভবত, তাই লাইনস্ট্রিংগুলি সবসময় এই পরিস্থিতিতে কার্যকর হয় না :( অবশ্যই, এই জাতীয় ডেটা হিসাবে সংরক্ষণ করা উচিত যেহেতু আপনার ডেটা সময়ে নিয়মিত পয়েন্টগুলিতে নমুনাযুক্ত কোনও অবজেক্টের বিচ্ছিন্ন অবস্থানের প্রতিনিধিত্ব করে a
আপনার ক্ষেত্রে এটি ঠিক জরিমানা করেছে:
select geometry::STGeomFromText('MULTIPOINT (0 0 1, 0 1 2, 0 -1 3)',4326)
.IsValidDetailed()
24400: Valid
আপনার যদি একে একে লাইনস্ট্রিং হিসাবে বজায় রাখতে হয় তবে জেড সংরক্ষণ করার সময় আপনার নিজের সংস্করণটি MakeValid
কিছুটা X বা Y পয়েন্টকে সামান্য সামঞ্জস্য করে লিখতে হবে (এবং অন্যান্য পাগল জিনিসগুলি যেমন করেন না এটিকে অন্য বস্তুর ধরণে রূপান্তর করুন)।
আমি এখনও কিছু কোড নিয়ে কাজ করছি, তবে এখানে কিছু প্রাথমিক ধারণাটি দেখুন:
সম্পাদনা করুন ঠিক আছে, পরীক্ষার সময় আমি কয়েকটি জিনিস পেয়েছি:
- যদি জ্যামিতি অবজেক্টটি অবৈধ হয় তবে আপনি এটির সাথে খুব বেশি কিছু করতে পারবেন না। আপনি এটি পড়তে পারবেন না
STGeometryType
, আপনি সেগুলি মাধ্যমে পুনরাবৃত্তি করতে পারবেন না STNumPoints
বা ব্যবহার করতে পারবেন না STPointN
। যদি আপনি ব্যবহার করতে না পারেন তবে MakeValid
আপনি মূলত ভৌগলিক অবজেক্টের পাঠ্য উপস্থাপনের জন্য অপারেটিং নিয়ে আটকে আছেন।
- ব্যবহারের
STAsText()
ফলে এমনকি কোনও অবৈধ অবজেক্টের পাঠ্য উপস্থাপনাও ফিরে আসবে, তবে জেড বা এম মানগুলি দেয় না। পরিবর্তে, আমরা চাই AsTextZM()
বা ToString()
।
- আপনি কল করতে পারেন এমন ফাংশন তৈরি করতে পারবেন না
RAND()
(ফাংশনগুলিকে ডিটারমিনিস্টিক হওয়া দরকার), সুতরাং আমি কেবল এটিকে ক্রমাগত আরও বৃহত্তর এবং বৃহত্তর মানগুলিতে ঠেলে দিয়েছি। আপনার ডেটাটির যথার্থতা কী, বা ছোট পরিবর্তনগুলি কতটা সহনশীল তা আমার আসলেই ধারণা নেই, সুতরাং আপনার নিজের বিবেচনায় এই ফাংশনটি ব্যবহার বা সংশোধন করুন।
আমার কোনও ধারণা নেই যদি সেখানে কোনও সম্ভাব্য ইনপুট থাকে যা এই লুপটি চিরতরে চলে যেতে পারে। তোমাকে সতর্ক করা হইছে.
CREATE FUNCTION dbo.FixBadLineString (@input geography) RETURNS geography
AS BEGIN
DECLARE @output geography
IF @input.STIsValid() = 1 --send valid objects back as-is
SET @output = @input;
ELSE IF LEFT(@input.IsValidDetailed(),6) = '24413:'
--"Not valid because of two overlapping edges in curve"
BEGIN
--make a new MultiPoint object from the LineString text
DECLARE @mp geography = geography::STGeomFromText(
REPLACE(@input.AsTextZM(), 'LINESTRING', 'MULTIPOINT'), 4326);
DECLARE @newText nvarchar(max); --to build output
DECLARE @point int
DECLARE @tinynum float = 0;
SET @output = @input;
--keep going until it validates
WHILE @output.STIsValid() = 0
BEGIN
SET @newText = 'LINESTRING (';
SET @point = 1
SET @tinynum = @tinynum + 0.00000001
--Loop through the points, add a bit and append to the new string
WHILE @point <= @mp.STNumPoints()
BEGIN
SET @newText = @newText + convert(varchar(50),
@mp.STPointN(@point).Long + @tinynum) + ' ';
SET @newText = @newText + convert(varchar(50),
@mp.STPointN(@point).Lat - @tinynum) + ' ';
SET @newText = @newText + convert(varchar(50),
@mp.STPointN(@point).Z) + ', ';
SET @tinynum = @tinynum * -2
SET @point = @point + 1
END
--close the parens and make the new LineString object
SET @newText = LEFT(@newText, LEN(@newText) - 1) + ')'
SET @output = geography::STGeomFromText(@newText, 4326);
END; --this will loop if it is still invalid
RETURN @output;
END;
--Any other unhandled error, just send back NULL
ELSE SET @output = NULL;
RETURN @output;
END
স্ট্রিংটিকে বিশ্লেষণের পরিবর্তে, MultiPoint
একই পয়েন্টগুলির সেটটি ব্যবহার করে আমি একটি নতুন অবজেক্ট তৈরি করতে বেছে নিয়েছি , তাই আমি তাদের মাধ্যমে পুনরাবৃত্তি করতে এবং তাদেরকে ন্যাজ করতে পারি, তারপরে একটি নতুন লাইনস্ট্রিংকে পুনরায় সংযুক্ত করতে পারি। এটি পরীক্ষা করার জন্য এখানে কিছু কোড রয়েছে, এর মধ্যে 3 টি মান (আপনার নমুনা সহ) অবৈধ শুরু করে তবে তা স্থির করা হয়েছে:
declare @geostuff table (baddata geography)
INSERT INTO @geostuff (baddata)
SELECT geography::STGeomFromText('LINESTRING (0 0 1, 0 1 2, 0 -1 3)',4326)
UNION ALL SELECT geography::STGeomFromText('LINESTRING (0 2 0, 0 1 0.5, 0 -1 -14)',4326)
UNION ALL SELECT geography::STGeomFromText('LINESTRING (0 0 4, 1 1 40, -1 -1 23)',4326)
UNION ALL SELECT geography::STGeomFromText('LINESTRING (1 1 9, 0 1 -.5, 0 -1 3)',4326)
UNION ALL SELECT geography::STGeomFromText('LINESTRING (6 6 26.5, 4 4 42, 12 12 86)',4326)
UNION ALL SELECT geography::STGeomFromText('LINESTRING (0 0 2, -4 4 -2, 4 -4 0)',4326)
SELECT baddata.AsTextZM() as before, baddata.IsValidDetailed() as pretest,
dbo.FixBadLineString(baddata).AsTextZM() as after,
dbo.FixBadLineString(baddata).IsValidDetailed() as posttest
FROM @geostuff