#include "GeomCoords.h" #pragma hdrstop NAMESPACE_UPP GisCoords::Arg GisCoords::Arg::Edit(double& v, String ident, String name, String help_topic, double min, double max, bool not_null) { Arg out; out.vtype = DOUBLE_V; out.ident = ident; out.name = name; out.help_topic = help_topic; out.style = STYLE_EDIT; out.min = min; out.max = max; out.not_null = not_null; out.ref = Ref(v); return out; } GisCoords::Arg GisCoords::Arg::Angle(double& v, String ident, String name, String help_topic, double min, double max, bool not_null) { Arg out; out.vtype = DOUBLE_V; out.ident = ident; out.name = name; out.help_topic = help_topic; out.style = STYLE_ANGLE; out.min = min; out.max = max; out.not_null = not_null; out.ref = Ref(v); return out; } GisCoords::Arg GisCoords::Arg::Edit(String& v, String ident, String name, String help_topic, bool not_null) { Arg out; out.vtype = STRING_V; out.ident = ident; out.name = name; out.help_topic = help_topic; out.style = STYLE_EDIT; out.not_null = not_null; out.ref = Ref(v); return out; } GisCoords::Arg GisCoords::Arg::Edit(Date& d, String ident, String name, String help_topic, bool not_null) { Arg out; out.vtype = DATE_V; out.ident = ident; out.name = name; out.help_topic = help_topic; out.style = STYLE_EDIT; out.not_null = not_null; out.ref = Ref(d); return out; } GisCoords::Arg GisCoords::Arg::Edit(Time& t, String ident, String name, String help_topic, bool not_null) { Arg out; out.vtype = TIME_V; out.ident = ident; out.name = name; out.help_topic = help_topic; out.style = STYLE_EDIT; out.not_null = not_null; out.ref = Ref(t); return out; } GisCoords::Arg GisCoords::Arg::DropList(String& v, String ident, String name, String help_topic, String variants, bool not_null) { Arg out; out.vtype = STRING_V; out.ident = ident; out.name = name; out.help_topic = help_topic; out.style = STYLE_DROPLIST; out.variants = variants; out.not_null = not_null; out.ref = Ref(v); return out; } GisCoords::Arg GisCoords::Arg::Option(bool& b, String ident, String name, String help_topic) { Arg out; out.vtype = INT_V; out.ident = ident; out.name = name; out.help_topic = help_topic; out.style = STYLE_OPTION; out.not_null = true; out.ref = BoolAsRef(b); return out; } GisCoords::Arg GisCoords::Arg::Option3(int& b, String ident, String name, String help_topic) { Arg out; out.vtype = INT_V; out.ident = ident; out.name = name; out.help_topic = help_topic; out.style = STYLE_OPTION3; out.not_null = false; out.ref = Ref(b); return out; } GisCoords::Data::Data() { epsg_code = 0; lonlat_limits = Rectf(-180, -90, 180, 90); } bool GisCoords::Data::IsProjected() const { return true; } int GisCoords::Data::GetBranchCount() const { return 1; } Array GisCoords::Data::LonLatBoundary(const Rectf& lonlat_extent, int b) const { Array out; out.SetCount(5); out[0] = lonlat_extent.TopLeft(); out[1] = lonlat_extent.TopRight(); out[2] = lonlat_extent.BottomRight(); out[3] = lonlat_extent.BottomLeft(); out[4] = lonlat_extent.TopLeft(); return out; } GisBSPTree GisCoords::Data::GetBranchTree(const Rectf& lonlat_extent) const { return GisBSPTree::Node(0); } Rectf GisCoords::Data::LonLatExtent(const Rectf& xy_extent) const { Rectf lonlat_extent = Null; lonlat_extent |= LonLat(xy_extent.TopLeft()); lonlat_extent |= LonLat(xy_extent.TopRight()); lonlat_extent |= LonLat(xy_extent.BottomLeft()); lonlat_extent |= LonLat(xy_extent.BottomRight()); return lonlat_extent; } Rectf GisCoords::Data::ProjectExtent(const Rectf& lonlat_extent) const { // ASSERT(GetBranchCount() == 1); Rectf xy_extent = Null; xy_extent |= Project(lonlat_extent.TopLeft(), 0); xy_extent |= Project(lonlat_extent.TopRight(), 0); xy_extent |= Project(lonlat_extent.BottomLeft(), 0); xy_extent |= Project(lonlat_extent.BottomRight(), 0); return xy_extent; } double GisCoords::Data::ProjectDeviation(Pointf lonlat1, Pointf lonlat2, int branch) const { Pointf mid = (lonlat1 + lonlat2) / 2.0; Pointf p1 = Project(lonlat1, branch), p2 = Project(mid, branch), p3 = Project(lonlat2, branch); Pointf pmid = (p1 + p3) / 2.0; double length = Distance(p1, p3); if(length <= 1e-10) return Distance(p2, pmid); return ((p1 - pmid) ^ (p3 - p1)) / length; } double GisCoords::Data::ProjectRatio(Pointf lonlat, int branch) const { Pointf proj = Project(lonlat, branch); static const double DELTA = 1e-3; Sizef east = Project(lonlat + Sizef(DELTA, 0), branch); Sizef north = Project(lonlat + Sizef(0, DELTA), branch); return (Length(east) + Length(north)) * (DELTA / 2); } double GisCoords::Data::ExtentDeviation(const Rectf& lonlat_extent) const { return 0; } Sizef GisCoords::Data::MinMaxRatio(const Rectf& lonlat_extent) const { return Sizef(1, 1); } bool GisCoords::Data::IsIdentity(const Data *data) const { if(strcmp(typeid(*this).name(), typeid(*data).name())) return false; Array args = const_cast(this)->EnumArgs(); Array args2 = const_cast(data)->EnumArgs(); if(args.GetCount() != args2.GetCount()) return false; for(int i = 0; i < args.GetCount(); i++) if(args[i].name != args2[i].name || args[i].vtype != args2[i].vtype || Value(args[i].ref) != Value(args2[i].ref)) return false; return true; } bool GisCoords::Equals(const GisCoords& co) const { bool na = IsNullInstance(), nb = co.IsNullInstance(); if(na || nb) return na && nb; return GetIdent() == co.GetIdent(); } class GisTransformIdentity : public GisTransform::Data { public: GisTransformIdentity() {} virtual GisTransform DeepCopy() const { return new GisTransformIdentity(*this); } virtual Pointf Target(Pointf s) const { return s; } virtual Pointf Source(Pointf t) const { return t; } virtual Rectf TargetExtent(const Rectf& s) const { return s; } virtual Rectf SourceExtent(const Rectf& t) const { return t; } virtual double SourceDeviation(Pointf src1, Pointf src2) const { return 0; } virtual double TargetDeviation(Pointf trg1, Pointf trg2) const { return 0; } virtual double SourceExtentDeviation(const Rectf& src) const { return 0; } virtual double TargetExtentDeviation(const Rectf& trg) const { return 0; } virtual Sizef SourceMinMaxRatio(const Rectf& s) const { return Sizef(1, 1); } virtual Sizef TargetMinMaxRatio(const Rectf& t) const { return Sizef(1, 1); } virtual GisBSPTree TargetBranchTree(const Rectf& t) const { return GisBSPTree(0); } virtual GisBSPTree SourceBranchTree(const Rectf& t) const { return GisBSPTree(0); } virtual Rectf TargetLimits() const { return Null; } virtual Rectf SourceLimits() const { return Null; } virtual bool IsProjected() const { return true; } virtual bool IsIdentity() const { return true; } }; class GisTransformProjectIdentity : public GisTransform::Data { public: GisTransformProjectIdentity(GisCoords st) { source = target = st; } virtual GisTransform DeepCopy() const { return new GisTransformProjectIdentity(*this); } virtual Pointf Target(Pointf s) const { return s; } virtual Pointf Source(Pointf t) const { return t; } virtual Rectf TargetExtent(const Rectf& s) const { return s; } virtual Rectf SourceExtent(const Rectf& t) const { return t; } virtual double SourceDeviation(Pointf src1, Pointf src2) const { return 0; } virtual double TargetDeviation(Pointf trg1, Pointf trg2) const { return 0; } virtual double SourceExtentDeviation(const Rectf& src) const { return 0; } virtual double TargetExtentDeviation(const Rectf& trg) const { return 0; } virtual Sizef SourceMinMaxRatio(const Rectf& s) const { return Sizef(1, 1); } virtual Sizef TargetMinMaxRatio(const Rectf& t) const { return Sizef(1, 1); } virtual GisBSPTree TargetBranchTree(const Rectf& t) const { return GisBSPTree(0); } virtual GisBSPTree SourceBranchTree(const Rectf& s) const { return GisBSPTree(0); } virtual Rectf TargetLimits() const { return target.ProjectExtent(source.LonLatLimits()); } virtual Rectf SourceLimits() const { return source.ProjectExtent(source.LonLatLimits()); } virtual bool IsProjected() const { return target.IsProjected(); } virtual bool IsIdentity() const { return true; } }; class GisTransformSameEllip : public GisTransform::Data { public: GisTransformSameEllip(GisCoords src, GisCoords trg) { source = src; target = trg; } virtual GisTransform DeepCopy() const { return new GisTransformSameEllip(*this); } virtual Pointf Target(Pointf s) const { return target.Project(source.LonLat(s), 0); } virtual Pointf Source(Pointf t) const { return source.Project(target.LonLat(t), 0); } virtual Rectf TargetExtent(const Rectf& s) const { return target.ProjectExtent(source.LonLatExtent(s)); } virtual Rectf SourceExtent(const Rectf& t) const { return source.ProjectExtent(target.LonLatExtent(t)); } virtual double SourceDeviation(Pointf src1, Pointf src2) const; virtual double TargetDeviation(Pointf trg1, Pointf trg2) const; virtual double SourceExtentDeviation(const Rectf& src) const; virtual double TargetExtentDeviation(const Rectf& trg) const; virtual Sizef SourceMinMaxRatio(const Rectf& s) const; virtual Sizef TargetMinMaxRatio(const Rectf& t) const; virtual GisBSPTree TargetBranchTree(const Rectf& t) const { return target.GetBranchTree(target.LonLatExtent(t)); } virtual GisBSPTree SourceBranchTree(const Rectf& s) const { return target.GetBranchTree(source.LonLatExtent(s)); } virtual Rectf TargetLimits() const { return target.ProjectExtent(source.LonLatLimits() & target.LonLatLimits()); } virtual Rectf SourceLimits() const { return source.ProjectExtent(source.LonLatLimits() & target.LonLatLimits()); } virtual bool IsProjected() const { return target.IsProjected(); } virtual bool IsIdentity() const { return false; } Matrixf3 source_ellip; Matrixf3 target_ellip; }; double GisTransformSameEllip::SourceDeviation(Pointf src1, Pointf src2) const { Pointf ll1 = source.LonLat(src1), ll2 = source.LonLat(src2); Rectf ll = SortRectf(ll1, ll2); return target.ProjectDeviation(ll1, ll2, 0) + source.ProjectDeviation(ll1, ll2, 0) * (target.MinMaxRatio(ll).cy / source.MinMaxRatio(ll).cx); } double GisTransformSameEllip::TargetDeviation(Pointf trg1, Pointf trg2) const { Pointf ll1 = target.LonLat(trg1), ll2 = target.LonLat(trg2); Rectf ll = SortRectf(ll1, ll2); return target.ProjectDeviation(ll1, ll2, 0) + source.ProjectDeviation(ll1, ll2, 0) * (target.MinMaxRatio(ll).cy / source.MinMaxRatio(ll).cx); } double GisTransformSameEllip::SourceExtentDeviation(const Rectf& src) const { Rectf ll = source.LonLatExtent(src); return target.ExtentDeviation(ll) + source.ExtentDeviation(ll) * (target.MinMaxRatio(ll).cy / source.MinMaxRatio(ll).cx); } double GisTransformSameEllip::TargetExtentDeviation(const Rectf& trg) const { Rectf ll = target.LonLatExtent(trg); return target.ExtentDeviation(ll) + source.ExtentDeviation(ll) * (target.MinMaxRatio(ll).cy / source.MinMaxRatio(ll).cx); } Sizef GisTransformSameEllip::SourceMinMaxRatio(const Rectf& s) const { Rectf ll = source.LonLatExtent(s); Sizef sr = source.MinMaxRatio(ll); Sizef dr = target.MinMaxRatio(ll); return Sizef(dr.cx / sr.cy, dr.cy / sr.cx); } Sizef GisTransformSameEllip::TargetMinMaxRatio(const Rectf& t) const { Rectf ll = target.LonLatExtent(t); Sizef sr = source.MinMaxRatio(ll); Sizef dr = target.MinMaxRatio(ll); return Sizef(dr.cx / sr.cy, dr.cy / sr.cx); } class GisTransformGeneric : public GisTransform::Data { public: GisTransformGeneric(GisCoords src, GisCoords trg); virtual GisTransform DeepCopy() const { return new GisTransformGeneric(*this); } virtual Pointf Target(Pointf s) const; virtual Pointf Source(Pointf t) const; virtual Rectf TargetExtent(const Rectf& s) const; virtual Rectf SourceExtent(const Rectf& t) const; virtual double SourceDeviation(Pointf src1, Pointf src2) const; virtual double TargetDeviation(Pointf trg1, Pointf trg2) const; virtual double SourceExtentDeviation(const Rectf& src) const; virtual double TargetExtentDeviation(const Rectf& trg) const; virtual Sizef SourceMinMaxRatio(const Rectf& s) const; virtual Sizef TargetMinMaxRatio(const Rectf& t) const; virtual GisBSPTree TargetBranchTree(const Rectf& t) const { return target.GetBranchTree(target.LonLatExtent(t)); } virtual GisBSPTree SourceBranchTree(const Rectf& s) const { return target.GetBranchTree(source.LonLatExtent(s)); } virtual Rectf TargetLimits() const { return target.ProjectExtent(source.LonLatLimits() & target.LonLatLimits()); } virtual Rectf SourceLimits() const { return source.ProjectExtent(source.LonLatLimits() & target.LonLatLimits()); } virtual bool IsProjected() const { return target.IsProjected(); } virtual bool IsIdentity() const { return false; } Matrixf3 source_ellip; Matrixf3 target_ellip; }; GisTransformGeneric::GisTransformGeneric(GisCoords src, GisCoords trg) { source = src; target = trg; target_ellip = Matrixf3Inverse(source.FromWGS84()) * target.FromWGS84(); source_ellip = Matrixf3Inverse(target_ellip); } Pointf GisTransformGeneric::Target(Pointf s) const { return target.Project3D(source.LonLat3D(s) * target_ellip, 0); } Pointf GisTransformGeneric::Source(Pointf t) const { return source.Project3D(target.LonLat3D(t) * source_ellip, 0); } Rectf GisTransformGeneric::TargetExtent(const Rectf& s) const { Rectf lonlat = source.LonLatExtent(s); Rectf lontar = Null; lontar |= target.From3D(source.To3D(lonlat.TopLeft()) * target_ellip); lontar |= target.From3D(source.To3D(lonlat.TopRight()) * target_ellip); lontar |= target.From3D(source.To3D(lonlat.BottomLeft()) * target_ellip); lontar |= target.From3D(source.To3D(lonlat.BottomRight()) * target_ellip); return target.ProjectExtent(lontar); } Rectf GisTransformGeneric::SourceExtent(const Rectf& t) const { Rectf lonlat = target.LonLatExtent(t); Rectf lonsrc = Null; lonsrc |= source.From3D(target.To3D(lonlat.TopLeft()) * source_ellip); lonsrc |= source.From3D(target.To3D(lonlat.TopRight()) * source_ellip); lonsrc |= source.From3D(target.To3D(lonlat.BottomLeft()) * source_ellip); lonsrc |= source.From3D(target.To3D(lonlat.BottomRight()) * source_ellip); return source.ProjectExtent(lonsrc); } double GisTransformGeneric::SourceDeviation(Pointf src1, Pointf src2) const { Pointf ll1 = source.LonLat(src1), ll2 = source.LonLat(src2); Rectf ll = SortRectf(ll1, ll2); return target.ProjectDeviation(ll1, ll2, 0) + source.ProjectDeviation(ll1, ll2, 0) * (target.MinMaxRatio(ll).cy / source.MinMaxRatio(ll).cx); } double GisTransformGeneric::TargetDeviation(Pointf trg1, Pointf trg2) const { Pointf ll1 = target.LonLat(trg1), ll2 = target.LonLat(trg2); Rectf ll = SortRectf(ll1, ll2); return target.ProjectDeviation(ll1, ll2, 0) + source.ProjectDeviation(ll1, ll2, 0) * (target.MinMaxRatio(ll).cy / source.MinMaxRatio(ll).cx); } double GisTransformGeneric::SourceExtentDeviation(const Rectf& src) const { Rectf ll = source.LonLatExtent(src); return target.ExtentDeviation(ll) + source.ExtentDeviation(ll) * (target.MinMaxRatio(ll).cy / source.MinMaxRatio(ll).cx); } double GisTransformGeneric::TargetExtentDeviation(const Rectf& trg) const { Rectf ll = target.LonLatExtent(trg); return target.ExtentDeviation(ll) + source.ExtentDeviation(ll) * (target.MinMaxRatio(ll).cy / source.MinMaxRatio(ll).cx); } Sizef GisTransformGeneric::SourceMinMaxRatio(const Rectf& s) const { Rectf ll = source.LonLatExtent(s); Sizef sr = source.MinMaxRatio(ll); Sizef dr = target.MinMaxRatio(ll); return Sizef(dr.cx / sr.cy, dr.cy / sr.cx); } Sizef GisTransformGeneric::TargetMinMaxRatio(const Rectf& t) const { Rectf ll = target.LonLatExtent(t); Sizef sr = source.MinMaxRatio(ll); Sizef dr = target.MinMaxRatio(ll); return Sizef(dr.cx / sr.cy, dr.cy / sr.cx); } GisTransform::GisTransform(const Nuller&) : data(new GisTransformIdentity) {} GisTransform::GisTransform(GisCoords src, GisCoords dest) { if(IsNull(src) && IsNull(dest)) data = new GisTransformIdentity(); else if(IsNull(src)) data = new GisTransformProjectIdentity(dest); else if(IsNull(dest)) data = new GisTransformProjectIdentity(src); else if(src.IsIdentity(dest)) data = new GisTransformProjectIdentity(dest); else if(src.GetEllipsoid() == dest.GetEllipsoid()) data = new GisTransformSameEllip(src, dest); else data = new GisTransformGeneric(src, dest); } bool GisTransform::Equals(const GisTransform& t) const { return Source() == t.Source() && Target() == t.Target(); } END_UPP_NAMESPACE