Manual convertCoordinate toPointToView

I wonder if anyone has done manual calculation to map a WGS84 coordinate to the UIView coordinates system? Indeed I convert WGS84 to ENU coordinate system which is similar to Cartesian (x,y,z) coordinate system.

I know there is a method in MKMapView which gets a CLLocationCoordinate2D and returns a CGPoint in an expected UIView, but I want to draw the CGPoints on a blank UIView rather than on a map. Therefore I'd like to skip initializing MKMapView object just to use this method.

There must be a simple way to scale down the coordinates from Cartesian to device coordinate system. I guess I also need to have some form of rotation/transformation for origin of the system (Cartesian -> UIView) as the origin point for UIView sits on top-left.

Answers


Shrinking down the coordinates should be straight forward.

Lets say you have a cluster of coordinates around a ridiculous point (32000, 192033). This is the centre point of that particular cluster.

Obviously we want to shift them so that they are centred around the origin (0, 0).

So take every point and convert it using...

newPoint = CGPointMake(oldPoint.x - 32000, oldPoint.y - 192033)

This will bring them all so that they are all the same relative distance apart but now centred on the origin.

Next, say the minimum X value is -9345 and the maximum X value is 8455.

You want your X range to be something like 640 (to fit all of them across the screen).

So...

currentXRange = 8455 + 9345; // maxX - minX = 17800
requiredXRange = 640;
xScale = requiredXRange / currentXRange; // 0.0359...

Now that you have an x scale you can convert your points by multiplying the x coordinate by the xScale value.

The minimum X value you have will be...

-9345 * xScale; // -335.4...

Maximum X value will be...

8455 * xScale; // 303.5...
EDIT so they are on screen

To bring them all so they are greater than 0. (i.e. so they are all on the screen) just subtract the smallest X and Y coordinate values from each of the points.

-335.4 - (-335.4) = 0 // minimum X value
303.5 - (-335.4) = 638.9 // maximum X value

That brings them all in range so that they fit on the screen.

EDIT upside down Y axis

To make sure they are displayed the right way up just create the points by subtracting them from the height of the view.

If the view size is (100, 100) then a point (50, 10) in iOS will be in the middle near the top of the view.

But in normal use it should be near the bottom.

So create the converted point using...

convertedPoint = CGPointMake(originalPoint.x, view.height - originalPoint.y)

This will create the point (50, 90) which will put it in the middle and ten points from the bottom like you wanted.

NOTE

As long as you do the same operation to every point in the set then they will all be in the same relative place and the data will still be valid.

The tricky part is working out the operation but I think I've covered everything.


@Fogmeister, eventhough your answer makes sense on the paper I don't know why I can't get it to work. I have positons in enus array. I first found the minx, miny, maxx, maxy

    let sortX = enus.sort({ $0.epos < $1.epos })
    let sortY = enus.sort({ $0.npos < $1.npos })
    let minx = sortX.first?.epos
    let maxx = sortX.last?.epos
    let miny = sortY.first?.npos
    let maxy = sortY.last?.npos

Then I found the ranges:

        let xrange = abs(maxx!-minx!)
        let yrange = abs(maxy!-miny!)

Then I found the scale factor:

        let xscale = self.frame.size.width.asDouble / xrange
        let yscale = self.frame.size.height.asDouble / yrange
        let factor = (xscale <= yscale ? xscale : yscale)

Then in a loop I use the factor and minx and miny to scale down and shift my enu positions:

    points.removeAll()
    let minx_scaled = minx * factor
    let miny_scaled = miny * factor
    for enu in enus {
        let e_scaled   = enu.epos * factor
        let n_scaled   = enu.npos * factor

        let x = e_scaled - minx_scaled
        var y = n_scaled - miny_scaled
        y = self.frame.size.height.asDouble - y

        let point = CGPointMake(x.asCGFloat,y.asCGFloat)
        points.append(point)
    }

and here I draw the points:

private let path1 = UIBezierPath()
var moved = false
override func drawRect(rect: CGRect) {

    if points.count == 0 { return}

    if moved == false {
        path1.moveToPoint(points.first!)
        moved = true
    }else{
        path1.addLineToPoint(points.last!)
    }

    path1.lineWidth = 3
    path1.lineJoinStyle = .Round
    UIColor.whiteColor().setStroke()
    path1.stroke()
}

The image below is a blank UIView where I draw my UIBezierPath. I used a little mapview as a reference.


Need Your Help

SubstringToIndex memory leak

objective-c memory-leaks substring

I'm using this function to extract a substring, it works but there are two leaks:

String formatting c# decode?

c# json character-encoding serialization

I have a string which looks like this '%7B%22id%22%3A1%2C%22name%22%3A%22jim%22%7D' When read from a cookie it is in fact a JSON object and should look like {"id":1,"name":"jim"}