diff --git a/400_xowa/src/gplx/xowa/xtns/wbases/Wdata_prop_val_visitor.java b/400_xowa/src/gplx/xowa/xtns/wbases/Wdata_prop_val_visitor.java index b015064a2..36823aada 100644 --- a/400_xowa/src/gplx/xowa/xtns/wbases/Wdata_prop_val_visitor.java +++ b/400_xowa/src/gplx/xowa/xtns/wbases/Wdata_prop_val_visitor.java @@ -23,15 +23,16 @@ import gplx.Bry_find_; import gplx.Byte_ascii; import gplx.Decimal_adp; import gplx.Decimal_adp_; +import gplx.Double_; import gplx.Err_; import gplx.Gfo_usr_dlg_; import gplx.Math_; -import gplx.Object_; import gplx.String_; import gplx.core.brys.fmtrs.Bry_fmtr; import gplx.xowa.Xoae_app; import gplx.xowa.langs.Xol_lang_itm; import gplx.xowa.langs.Xol_lang_itm_; +import gplx.xowa.xtns.mapSources.Map_dd2dms_func; import gplx.xowa.xtns.wbases.claims.Wbase_claim_visitor; import gplx.xowa.xtns.wbases.claims.itms.Wbase_claim_entity; import gplx.xowa.xtns.wbases.claims.itms.Wbase_claim_globecoordinate; @@ -182,21 +183,45 @@ public class Wdata_prop_val_visitor implements Wbase_claim_visitor { // THREAD.U } public void Visit_globecoordinate(Wbase_claim_globecoordinate itm) {Write_geo(Bool_.N, bfr, wdata_mgr.Hwtr_mgr().Lbl_mgr(), msgs, itm.Lat(), itm.Lng(), itm.Alt(), itm.Prc(), itm.Glb());} public static void Write_geo(boolean wikidata_page, Bry_bfr bfr, Wdata_lbl_mgr lbl_mgr, Wdata_hwtr_msgs msgs, byte[] lat, byte[] lng, byte[] alt, byte[] prc, byte[] glb) { - // get precision - int precision_int = -1; - if (Bry_.Eq(prc, Object_.Bry__null) || Bry_.Eq(prc, Byte_ascii.Num_0_bry)) // "null" or "0" should be 1; PAGE:ru.w:Лысково_(Калужская_область) DATE:2016-11-24 - precision_int = 1; + // 2020-09-06|ISSUE#:792|rewrite based on https://en.wikipedia.org/w/index.php?title=Module:Wd&action=edit; REF.MW: https://github.com/DataValues/Geo/blob/master/src/Formatters/LatLongFormatter.php + // normalize precision + double precision = Double_.parse_or(String_.new_a7(prc), Double_.NaN); + if (Double_.IsNaN(precision) || precision <= 0) { // "null" or "0" should be 1; PAGE:ru.w:Лысково_(Калужская_область) DATE:2016-11-24 + precision = PRECISION_1_OVER_3600; + } + + double latitude = Double_.parse_or(String_.new_a7(lat), Double_.NaN); + double longitude = Double_.parse_or(String_.new_a7(lng), Double_.NaN); + latitude = Math_.Floor(latitude / precision + 0.5) * precision; + longitude = Math_.Floor(longitude / precision + 0.5) * precision; + + if (precision >= 1 - (PRECISION_1_OVER_60) && precision < 1) { + precision = 1; + } + else if (precision >= (PRECISION_1_OVER_60) - (PRECISION_1_OVER_3600) && precision < PRECISION_1_OVER_60) { + precision = PRECISION_1_OVER_60; + } + + int unitsPerDegree = 1; + if (precision >= 1) { + unitsPerDegree = 1; + } + else if (precision >= PRECISION_1_OVER_60) { + unitsPerDegree = 60; + } else { - Decimal_adp precision_frac = Decimal_adp_.parse(String_.new_a7(prc)); - precision_int = Math_.Log10(Decimal_adp_.One.Divide(precision_frac).To_int()); // convert precision to log10 integer; EX: .00027777 -> 3600 -> 3 + unitsPerDegree = 3600; } - // build String - gplx.xowa.xtns.mapSources.Map_dd2dms_func.Deg_to_dms(bfr, Bool_.Y, Bool_.N, lat, precision_int); + int numDigits = (int)Math_.Ceil(-Math.log10(((double)(unitsPerDegree) * precision))); + numDigits += 4; // +4 b/c Map_dd2dms_func.Deg_to_dms needs 4 places to evaluate MS while fracs are evaulated as numDigits + + // write lat / lng + Map_dd2dms_func.Deg_to_dms(bfr, Bool_.Y, Bool_.N, Bry_.new_a7(Double_.To_str(latitude)), numDigits); bfr.Add_byte_comma().Add_byte_space(); - gplx.xowa.xtns.mapSources.Map_dd2dms_func.Deg_to_dms(bfr, Bool_.Y, Bool_.Y, lng, precision_int); + Map_dd2dms_func.Deg_to_dms(bfr, Bool_.Y, Bool_.Y, Bry_.new_a7(Double_.To_str(longitude)), numDigits); - // write globe if any + // write globe if (wikidata_page) { byte[] glb_ttl = Wdata_lbl_itm.Extract_ttl(glb); if (glb_ttl != null) { @@ -207,7 +232,11 @@ public class Wdata_prop_val_visitor implements Wbase_claim_visitor { // THREAD.U } } } + private static final double + PRECISION_1_OVER_3600 = 1d / 3600d + , PRECISION_1_OVER_60 = 1d / 60d + ; - private static final byte[] Wikidata_url = Bry_.new_a7("http://www.wikidata.org/entity/"); + private static final byte[] Wikidata_url = Bry_.new_a7("http://www.wikidata.org/entity/"); public void Visit_system(Wbase_claim_value itm) {} } diff --git a/400_xowa/src/gplx/xowa/xtns/wbases/Wdata_wiki_mgr_tst.java b/400_xowa/src/gplx/xowa/xtns/wbases/Wdata_wiki_mgr_tst.java index abb8bccce..e6c8272c9 100644 --- a/400_xowa/src/gplx/xowa/xtns/wbases/Wdata_wiki_mgr_tst.java +++ b/400_xowa/src/gplx/xowa/xtns/wbases/Wdata_wiki_mgr_tst.java @@ -1,6 +1,6 @@ /* XOWA: the XOWA Offline Wiki Application -Copyright (C) 2012-2017 gnosygnu@gmail.com +Copyright (C) 2012-2020 gnosygnu@gmail.com XOWA is licensed under the terms of the General Public License (GPL) Version 3, or alternatively under the terms of the Apache License Version 2.0. @@ -13,70 +13,104 @@ The terms of each license can be found in the source code repository: GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt */ -package gplx.xowa.xtns.wbases; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; -import org.junit.*; import gplx.core.tests.*; import gplx.xowa.xtns.wbases.imports.*; -public class Wdata_wiki_mgr_tst { - private final Wdata_prop_val_visitor__fxt fxt = new Wdata_prop_val_visitor__fxt(); - @Test public void Basic() { - Wdata_wiki_mgr_fxt fxt = new Wdata_wiki_mgr_fxt().Init(); - fxt.Init__docs__add(fxt.Wdoc("Q1") - .Add_sitelink("enwiki", "Q1_en") - ); - - fxt.Test_link("Q1_en" , "Q1"); - fxt.Test_link("Q1_nil", null); - } - @Test public void Case_sensitive() { // PURPOSE: wikidata lkp should be case_sensitive; a vs A DATE:2013-09-03 - Wdata_wiki_mgr_fxt fxt = new Wdata_wiki_mgr_fxt().Init(); - fxt.Init__docs__add(fxt.Wdoc("Q1") - .Add_sitelink("enwiki", "Q1_EN") - ); - - fxt.Test_link("Q1_EN", "Q1"); - fxt.Test_link("q1_en", null); - } - @Test public void Non_canonical_ns() { // PURPOSE: handle wikidata entries in non-canonical ns; EX:ukwikisource and Author; PAGE:uk.s:Автор:Богдан_Гаврилишин DATE:2014-07-23 - Wdata_wiki_mgr_fxt fxt = new Wdata_wiki_mgr_fxt().Init(); - Xowe_wiki wiki = fxt.Wiki(); - wiki.Ns_mgr().Add_new(124, "Test_ns"); - fxt.Init__docs__add(fxt.Wdoc("Q1") - .Add_sitelink("enwiki", "Test_ns:Test_page") - ); - - fxt.Test_link(Xoa_ttl.Parse(fxt.Wiki(), 124, Bry_.new_a7("Test_page")), "Q1"); // NOTE: wdata will save to "000" ns, b/c "124" ns is not canonical - } - @Test public void Write_json_as_html() { - Wdata_wiki_mgr_fxt fxt = new Wdata_wiki_mgr_fxt().Init(); - fxt.Test_write_json_as_html("{'a':'b','c':['d','e'],'f':{'g':''}}", String_.Concat_lines_nl_skip_last - ( "" - , "{ \"a\":\"b\"" - , ", \"c\":" - , " [ \"d\"" - , " , \"e\"" - , " ]" - , ", \"f\":" - , " { \"g\":\"<h>\"" - , " }" - , "}" - , "" - )); - } - @Test public void Normalize_for_decimal() { - fxt.Test__normalize_for_decimal("1234" , "1234"); // basic - fxt.Test__normalize_for_decimal("+1234" , "1234"); // plus - fxt.Test__normalize_for_decimal("1,234" , "1234"); // comma - fxt.Test__normalize_for_decimal("+1,234" , "1234"); // both - } - @Test public void Write_quantity_null() { // handle missing lbound / ubound; DATE:2016-12-03 - Wdata_wiki_mgr_fxt fxt = new Wdata_wiki_mgr_fxt().Init(); - - Bry_bfr bfr = Bry_bfr_.New(); - Wdata_prop_val_visitor.Write_quantity(bfr, fxt.Wdata_mgr(), fxt.Wiki().Lang(), Bry_.new_a7("123"), null, null, null); - Gftest.Eq__str("123", bfr.To_bry_and_clear()); - } -} -class Wdata_prop_val_visitor__fxt { - public void Test__normalize_for_decimal(String raw, String expd) { - Gftest.Eq__str(expd, Wdata_prop_val_visitor.Normalize_for_decimal(Bry_.new_u8(raw)), raw); - } -} +package gplx.xowa.xtns.wbases; + +import gplx.Bry_; +import gplx.Bry_bfr; +import gplx.Bry_bfr_; +import gplx.String_; +import gplx.core.tests.Gftest; +import gplx.xowa.Xoa_ttl; +import gplx.xowa.Xowe_wiki; +import gplx.xowa.xtns.wbases.hwtrs.Wdata_hwtr_msgs; +import gplx.xowa.xtns.wbases.hwtrs.Wdata_lbl_mgr; +import org.junit.Test; + +public class Wdata_wiki_mgr_tst { + private final Wdata_prop_val_visitor__fxt fxt = new Wdata_prop_val_visitor__fxt(); + @Test public void Basic() { + Wdata_wiki_mgr_fxt fxt = new Wdata_wiki_mgr_fxt().Init(); + fxt.Init__docs__add(fxt.Wdoc("Q1") + .Add_sitelink("enwiki", "Q1_en") + ); + + fxt.Test_link("Q1_en" , "Q1"); + fxt.Test_link("Q1_nil", null); + } + @Test public void Case_sensitive() { // PURPOSE: wikidata lkp should be case_sensitive; a vs A DATE:2013-09-03 + Wdata_wiki_mgr_fxt fxt = new Wdata_wiki_mgr_fxt().Init(); + fxt.Init__docs__add(fxt.Wdoc("Q1") + .Add_sitelink("enwiki", "Q1_EN") + ); + + fxt.Test_link("Q1_EN", "Q1"); + fxt.Test_link("q1_en", null); + } + @Test public void Non_canonical_ns() { // PURPOSE: handle wikidata entries in non-canonical ns; EX:ukwikisource and Author; PAGE:uk.s:Автор:Богдан_Гаврилишин DATE:2014-07-23 + Wdata_wiki_mgr_fxt fxt = new Wdata_wiki_mgr_fxt().Init(); + Xowe_wiki wiki = fxt.Wiki(); + wiki.Ns_mgr().Add_new(124, "Test_ns"); + fxt.Init__docs__add(fxt.Wdoc("Q1") + .Add_sitelink("enwiki", "Test_ns:Test_page") + ); + + fxt.Test_link(Xoa_ttl.Parse(fxt.Wiki(), 124, Bry_.new_a7("Test_page")), "Q1"); // NOTE: wdata will save to "000" ns, b/c "124" ns is not canonical + } + @Test public void Write_json_as_html() { + Wdata_wiki_mgr_fxt fxt = new Wdata_wiki_mgr_fxt().Init(); + fxt.Test_write_json_as_html("{'a':'b','c':['d','e'],'f':{'g':''}}", String_.Concat_lines_nl_skip_last + ( "" + , "{ \"a\":\"b\"" + , ", \"c\":" + , " [ \"d\"" + , " , \"e\"" + , " ]" + , ", \"f\":" + , " { \"g\":\"<h>\"" + , " }" + , "}" + , "" + )); + } + @Test public void Normalize_for_decimal() { + fxt.Test__normalize_for_decimal("1234" , "1234"); // basic + fxt.Test__normalize_for_decimal("+1234" , "1234"); // plus + fxt.Test__normalize_for_decimal("1,234" , "1234"); // comma + fxt.Test__normalize_for_decimal("+1,234" , "1234"); // both + } + @Test public void Write_quantity_null() { // handle missing lbound / ubound; DATE:2016-12-03 + Wdata_wiki_mgr_fxt fxt = new Wdata_wiki_mgr_fxt().Init(); + + Bry_bfr bfr = Bry_bfr_.New(); + Wdata_prop_val_visitor.Write_quantity(bfr, fxt.Wdata_mgr(), fxt.Wiki().Lang(), Bry_.new_a7("123"), null, null, null); + Gftest.Eq__str("123", bfr.To_bry_and_clear()); + } + @Test public void Geo() { + // null precision + fxt.TestGeo("39°57'42"N, 83°0'7"W", "39.96177", "-83.00196", "null"); + + // 1/60 precision + fxt.TestGeo("39°58'0"N, 83°0'0"W", "39.96177", "-83.00196", "0.0166666667"); + + // 1/3600 precision + fxt.TestGeo("39°57'42"N, 83°0'7"W", "39.96177", "-83.00196", "0.0002777778"); + + // 2020-09-06|ISSUE#:792|fails if 1 digit precision; EX: 42.4 instead of 42.37 + fxt.TestGeo("39°57'42.37"N, 83°0'7.06"W", "39.96177", "-83.00196", "1.0e-5"); + } +} +class Wdata_prop_val_visitor__fxt { + public void Test__normalize_for_decimal(String raw, String expd) { + Gftest.Eq__str(expd, Wdata_prop_val_visitor.Normalize_for_decimal(Bry_.new_u8(raw)), raw); + } + public void TestGeo(String expd, String lat, String lng, String prc) {TestGeo(expd, lat, lng, prc, null);} + public void TestGeo(String expd, String lat, String lng, String prc, String glb) { + boolean wikidata_page = glb != null; + Wdata_lbl_mgr lbl_mgr = new Wdata_lbl_mgr(); + Wdata_hwtr_msgs msgs = Wdata_hwtr_msgs.new_en_(); + Bry_bfr bfr = Bry_bfr_.New(); + + Wdata_prop_val_visitor.Write_geo(wikidata_page, bfr, lbl_mgr, msgs, Bry_.new_u8(lat), Bry_.new_u8(lng), null, Bry_.new_u8(prc), Bry_.new_u8_safe(glb)); + Gftest.Eq__str(expd, bfr.To_str_and_clear()); + } +}