Usage for plotAreaViewPointForPlotPoint in CorePlot 1.5.1 - ios

I'm trying to add something like UIPopoverController into the barPlot with coreplot 1.5.1 and swift. Like this one Core Plot: How to present popover from a bar selected by the user
So we need to know the point where the selected bar is ,But looks like some functions are different, like plotAreaViewPointForPlotPoint. In 1.5.1, there are two parameters:
And I'm try to find the right way to use it but failed, here is my code:
func barPlot(plot: CPTBarPlot!, barWasSelectedAtRecordIndex idx: UInt, withEvent event: UIEvent!) {
// Remove all the annotations
graphView.hostedGraph.plotAreaFrame.plotArea.removeAllAnnotations()
// Setup a style for the annotation
let hitAnnotationTextStyle = CPTMutableTextStyle.textStyle() as! CPTMutableTextStyle
hitAnnotationTextStyle.color = CPTColor.whiteColor()
hitAnnotationTextStyle.fontSize = 12.0;
hitAnnotationTextStyle.fontName = FONT_HEITI;
// Determine point of symbol in plot coordinates
let anchorPoint = [Int(idx),0]
// Add annotation
// First make a string for the y value
let string = "\(idx),values is:\(mArray.objectAtIndex(Int(idx)))"
// Now add the annotation to the plot area
let textLayer = CPTTextLayer(text: string, style: hitAnnotationTextStyle)
// popview, DxPopover is something like UIPopover Controller in iPhone
var popView = DXPopover()
annotationLabel.text = string
var pointers = [NSDecimal](count: 2, repeatedValue: CPTDecimalFromUnsignedInteger(0))
pointers[0] = CPTDecimalFromUnsignedInteger(idx)
var plotPointer: UnsafeMutablePointer<NSDecimal> = UnsafeMutablePointer<NSDecimal>.alloc(pointers.count)
plotPointer.initializeFrom(pointers)
var popPoint = graphView.hostedGraph.defaultPlotSpace.plotAreaViewPointForPlotPoint(plotPointer, numberOfCoordinates: idx)
popView.showAtPoint(popPoint, popoverPostion: DXPopoverPosition.Down, withContentView: self.annotationView, inView: graphView)
// selectedBarAnnotation = CPTPlotSpaceAnnotation(plotSpace: graphView.hostedGraph.defaultPlotSpace, anchorPlotPoint: anchorPoint)
// selectedBarAnnotation!.contentLayer = textLayer
// selectedBarAnnotation!.displacement = CGPointMake(0.0, -15.0)
// graphView.hostedGraph.plotAreaFrame.plotArea.addAnnotation(selectedBarAnnotation)
}
And it will crush at this line:
var popPoint = graphView.hostedGraph.defaultPlotSpace.plotAreaViewPointForPlotPoint(plotPointer, numberOfCoordinates: idx)
SO, HOW CAN I GET THE RIGHT CGPOINT?
Thanks very much!
=================EDIT===================
I change my codes to this, and can get the right point, Thanks to #Bannings
var popView = DXPopover()
annotationLabel.text = string
var pointers = [NSDecimal](count: 2, repeatedValue: CPTDecimalFromUnsignedInteger(0))
let plotXvalue = self.numberForPlot(plot, field: UInt(CPTScatterPlotFieldX.value), recordIndex: idx)
pointers[0] = CPTDecimalFromFloat(plotXvalue.floatValue)
println("\(CPTDecimalFromUnsignedInteger(idx))")
let plotspace = graphView.hostedGraph.defaultPlotSpace
println("\(plotspace.numberOfCoordinates)")
var popPoint = plotspace.plotAreaViewPointForPlotPoint(&pointers, numberOfCoordinates: plotspace.numberOfCoordinates)
popView.showAtPoint(popPoint, popoverPostion: DXPopoverPosition.Down, withContentView: self.annotationView, inView: graphView)

Try this:
var popPoint = graphView.hostedGraph.defaultPlotSpace.plotAreaViewPointForPlotPoint(&pointers, numberOfCoordinates: idx)

Related

Developing an ARKit app that leaves text for others to view

I am creating an iOS AR app that sets text in a specific location and leaves it there for others to view. Is there a better way to implement it than what I am doing?
Currently, I have it set so that the text is saved to Firebase and loads it by setting the nodes relative to the camera’s position. I’m wondering if there is a way to save ARAnchors in a fashion similar to what I am doing but is that possible?
My current function for saving the text to the location via a user tapping the screen:
/*
* Variables for saving the user touch
*/
var touchX : Float = 0.0
var touchY : Float = 0.0
var touchZ : Float = 0.0
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// will be used for getting the text
let textNode = SCNNode()
var writing = SCNText()
// gets the user’s touch upon tapping the screen
guard let touch = touches.first else {return}
let result = sceneView.hitTest(touch.location(in: sceneView), types: [ARHitTestResult.ResultType.featurePoint])
guard let hitResult = result.last else {return}
let hitTransform = SCNMatrix4.init(hitResult.worldTransform)
let hitVector = SCNVector3Make(hitTransform.m41, hitTransform.m42, hitTransform.m43)
// saves X, Y, and Z coordinates of touch relative to the camera
touchX = hitTransform.m41
touchY = hitTransform.m42
touchZ = hitTransform.m43
// Was thinking of adding the ability to change colors. Probably can skip next seven lines
var colorArray = [UIColor]()
colorArray.append(UIColor.red)
writing = SCNText(string: input.text, extrusionDepth: 1)
material.diffuse.contents = colorArray[0]
writing.materials = [material]
// modifies the node’s position and size
textNode.scale = SCNVector3(0.01, 0.01, 0.01)
textNode.geometry = writing
textNode.position = hitVector
sceneView.scene.rootNode.addChildNode(textNode)
// last few lines save the info to Firebase
let values = ["X" : touchX, "Y" : touchY, "Z" : touchZ, "Text" : input.text!] as [String : Any]
let childKey = reference.child("Test").childByAutoId().key
if input.text != nil && input.text != "" {
let child = reference.child("Test").child(childKey!)
child.updateChildValues(values)
} else {
let child = reference.child("Test").child(childKey!)
child.updateChildValues(values)
} // if
} // override func
/*
* Similar to the previous function but used in next function
*/
func placeNode(x: Float, y: Float, z: Float, text: String) -> Void {
let textNode = SCNNode()
var writing = SCNText()
let hitVector = SCNVector3Make(x, y, z)
touchX = x
touchY = y
touchZ = z
var colorArray = [UIColor]()
colorArray.append(UIColor.red)
writing = SCNText(string: text, extrusionDepth: 1)
material.diffuse.contents = colorArray[0]
writing.materials = [material]
textNode.scale = SCNVector3(0.01, 0.01, 0.01)
textNode.geometry = writing
textNode.position = hitVector
sceneView.scene.rootNode.addChildNode(textNode)
} // func
/*
* This next function is used in my viewDidLoad to load the data
*/
func handleData() {
reference.child("Test").observeSingleEvent(of: .value, with: { (snapshot) in
if let result = snapshot.children.allObjects as? [DataSnapshot] {
for child in result {
let xCoord = Float(truncating: child.childSnapshot(forPath: "X").value as! NSNumber)
let yCoord = Float(truncating: child.childSnapshot(forPath: "Y").value as! NSNumber)
let zCoord = Float(truncating: child.childSnapshot(forPath: "Z").value as! NSNumber)
let inscription = child.childSnapshot(forPath: "Text").value
self.placeNode(x: xCoord , y: yCoord , z: zCoord , text: inscription as! String)
} // for
} // if
}) // reference
} // func
I have looked into a few things such as ARCore but that looks like it uses Objective-C. I’ve made this app in Swift and I am not sure if I can incorporate ARCore with how I have implemented my current application.
Do I just need to get over it and learn Objective-C? Can I still work with what I have?
I think that ARCore anchors are only available for 24 hours, so that could be a problem.
You probably need to use ARKit2.0's ARWorldMap and save it as data on firebase for others to see the text in the same place, otherwise you are assuming in your code that future users will start their AR session in the exact same position and direction as the person who left the text. You probably need to use core location first to see where in the world the user is.

Find a plane position in ARKit

I was trying to find the position of the closest Plane in my ARKit app. I wrote some code to help find it, but for some reason, when I run my app, it keeps crashing when I try to add an AR object to the plane. Is there something wrong with my code?
struct myPlaneCoords {
var x = Float()
var y = Float()
var z = Float()
}
func getPlaneCoordinates(sceneView: ARSCNView) -> myPlaneCoords{//coordinates where an AR node will be added
let cameraTransform = sceneView.session.currentFrame?.camera.transform
let cameraCoordinates = MDLTransform(matrix: cameraTransform!)
let camX = CGFloat(cameraCoordinates.translation.x)
let camY = CGFloat(cameraCoordinates.translation.y)
let cameraPosition = CGPoint(x: camX, y: camY)
let anchors = sceneView.hitTest(cameraPosition, types: ARHitTestResult.ResultType.existingPlane)
let spefAnchor = MDLTransform(matrix: anchors[0].localTransform)//finds closest plane
var cc = myPlaneCoords()
cc.x = spefAnchor.translation.x
cc.y = spefAnchor.translation.y
cc.z = spefAnchor.translation.z
return cc
}
Difficult to judge w/o exception description.
I can assume that hitTest doesn't detect any anchor.
In such case your anchors is empty.
let spefAnchor = MDLTransform(matrix: anchors[0].localTransform)//finds closest plane
And here you should get a crash.

GMSMarker infowindow content(snippet) not updating

I have an array in which each element has Latitude Longitude and some other values in it to draw marker on map. I'm using the following code to update the snippet, position and icon of GMSMarker. I'm using a UISlider to iterate through the array. When I do this the icon and position of the marker gets updated and the InfoWindow of the marker not updating. It shows only the old content. But when I deselect and select it again now it shows correct infowindow content. I have tried to use tracksInfoWindowChanges, but it's not working.
#IBAction func progressChanged(_ sender: UISlider) {
let iVal = Int(sender.value)
if iVal < progressList.count {
let str = progressList[iVal]
let arr = str.components(separatedBy: "!")
let lat = Double(arr[4])!
let lng = Double(arr[5])!
let pos = CLLocationCoordinate2DMake(lat, lng)
let fRotation = Float(arr[9])
let rotation = CGFloat(fRotation!)
let strTime = arr[0]
let idleFlag = arr[1]
let strSpeed = arr[2]
let strName = arr[3]
proMarker.position = pos
proMarker.title = strName
if idleFlag == "Y" {
proMarker.snippet = strSpeed + "!" + strTime + "!" + "idle"
proMarker.tracksInfoWindowChanges = true
let markerImage = UIImage(named: "arrow_red")
let rotated = markerImage?.imageRotatedByDegrees(rotation, flip: false)
proMarker.icon = rotated
} else {
proMarker.snippet = strSpeed + "!" + strTime + "!" + "moving"
proMarker.tracksInfoWindowChanges = true
let markerImage = UIImage(named: "arrow_green")
let rotated = markerImage?.imageRotatedByDegrees(rotation, flip: false)
proMarker.icon = rotated
}
proMarker.groundAnchor = CGPoint(x: 0.5, y: 0.5)
let dTime = sdf5.date(from: strTime)
let sTime = sdf6.string(from: dTime!)
hTime.text = sTime
hSpeedIdle.text = strSpeed + " km/h"
}
}
Please help me solve my problem.
This is not a correct way to add lat_long, You should add marker_obj into array because each marker contain all related info, and it can help you to reduce such type of length of code.
As mentioned in a comment, it may be that you are not making new markers, or if you are, you need to remove the map from the old markers (marker.map = nil). So when you click on overlapped markers, the infowindows will sequentially appear.

Choose UIlabel background Color from Array and then remove it from array. (swift)

I have 3 UiLabels onscreen. I have an array with colors e.g. red,green,blue. I want to set the background of each UiLabel to a a color in the array and then delete the Color from the array so no 2 UiLabels have the same Color.
I was trying to do something like this. it selects a random string in the array but then i cannot assign it to the uilabel because its not of type UIColor.
override func viewDidLoad() {
super.viewDidLoad()
let Colorarray = ["UIColor.redColor()", "UIColor.greenColor()", "UIColor.blueColor()"]
let randomIndex = Int(arc4random_uniform(UInt32(Colorarray.count)))
print(randomIndex)
self.left.text = (Colorarray[randomIndex])
self.left.backgroundColor = (Colorarray[randomIndex])
self.middle.backgroundColor = (Colorarray[randomIndex])
self.right.backgroundColor = (Colorarray[randomIndex])
}
this was the second code i tried
var colorArray = [(UIColor.redColor(), "Red"), (UIColor.greenColor(), "Green"), (UIColor.blueColor(), "Blue")]
//random color
let randomIndex = Int(arc4random_uniform(UInt32(colorArray.count)))
//accessing color
var (color, name) = colorArray[randomIndex]
self.left.text = name
self.left.backgroundColor = color
let leftColorRemoval = (colorArray.removeAtIndex(randomIndex))
print(leftColorRemoval)
var (mcolor, mname) = colorArray[randomIndex]
self.middle.text = mname
self.middle.backgroundColor = mcolor
let middleColorRemoval = (colorArray.removeAtIndex(randomIndex))
print(middleColorRemoval)
var (rcolor, rname) = colorArray[randomIndex]
self.right.text = rname
self.right.backgroundColor = rcolor
let rightColorRemoval = (colorArray.removeAtIndex(randomIndex))
print(rightColorRemoval)
You can store an array of tuples that include both the actual UIColor and the string value. This makes it so you can provide any string value you want:
let colorArray = [(UIColor.redColor(), "Red"), (UIColor.greenColor(), "Green"), (UIColor.blueColor(), "Blue")]
Then, to access a random color:
let (color, name) = colorArray[randomIndex]
self.left.text = name
self.left.backgroundColor = color
...
It seems to me that your code doesn't actually remove random colors. Here's how you would actually do it (one of many ways):
let random = { () -> Int in
return Int(arc4random_uniform(UInt32(colorArray.count)))
} // makes random number, you can make it more reusable
let (leftColor, leftName) = colorArray.removeAtIndex(random()) // removeAtIndex: returns the removed tuple
let (middleColor, middleName) = colorArray.removeAtIndex(random())
let (rightColor, rightName) = colorArray.removeAtIndex(random())

Local variable won't copy to global variable

I need to copy a local variable tuple (sortedMarkers) from the function closestMarker() into the global variable sortedMarkerGlobal, however it doesn't seem to be working thus far. I want to use sortedMarkersGlobal in another function but it's count is zero (empty).
class MapViewController: UIViewController {
#IBOutlet weak var mapView: GMSMapView!
var sortedMarkerGlobal: [(lat: String, long: String)] = []
var nextParkCount: Int = 1 // Used to iterate over sortedMarkers with nextPark IBAction button
let locationManager = CLLocationManager()
var lastLocation: CLLocation? = nil // Create internal value to store location from didUpdateLocation to use in func showDirection()
var isAnimating: Bool = false
var dropDownViewIsDisplayed: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
....
}
func closestMarker(userLat: Double, userLong: Double)-> [(lat: String, long: String)] {
/*
var lengthRow = firstRow.count
while (sortedMarkers.count != lengthRow) { // There are markers that haven't been added to sortedMarkers
// Haversine formula
// add nearest marker to sortedMarkers
// Remove recently added marker from ParseViewControler() type tuple
// Recurse until all markers are in sortedMarkers
}
*/
let markerToTest = ParseViewController()
let firstRow = markerToTest.returnParse()
let lat2 = degreesToRadians(userLat) // Nearest lat in radians
let long2 = degreesToRadians(userLong) // Nearest long in radians
let R = (6371).doubleValue // Radius of earth in km
var closestLat: Double? = nil // Used to store the latitude of the closest marker
var closestLong: Double? = nil // Used to store the longitude of the closest marker
//
var indexToDelete: Int = 0 // Used to delete the marker which has been added to sortedMarkers tuple
let lengthRow = firstRow.count
var latLongs: (String, String)
var sortedMarkers: [(lat: String, long: String)] = []
var dynamicRow = firstRow // Tuple that has markers deleted from it
while (sortedMarkers.count != lengthRow) { // Store markers from closest to furtherst distance from user
var shortestDistance = 100.00E100
for (var i = 0; i < dynamicRow.count; i++) {
let testMarker = dynamicRow[i]
let testLat = (testMarker.lat as NSString)
let testLong = (testMarker.long as NSString)
let doubleLat = Double(testLat as String)
let doubleLong = Double(testLong as String)
let lat1 = degreesToRadians(doubleLat!)
let long1 = degreesToRadians(doubleLong!)
let dLat = lat2 - lat1
let dLong = long2 - long1
let a = ((sin((dLat)/2)) * (sin((dLat)/2))) + (cos(lat1)*cos(lat2)*((sin((dLong)/2)) * (sin((dLong)/2))))
let b = sqrt(a)
let d = (2*R) * (asin(b)) // Haversine formula
if (d < shortestDistance) {
closestLat = (doubleLat)
closestLong = (doubleLong)
shortestDistance = d
indexToDelete = i// Keep updating index of closest marker to later be removed
}
}
latLongs = (String(closestLat!), String(closestLong!)) // Each time for loop will find closest marker ~ NOT WORKING ~
sortedMarkers.append(latLongs)
dynamicRow.removeAtIndex(indexToDelete) // Remove marker that has just been added
}
sortedMarkerGlobal = sortedMarkers
return sortedMarkers
}

Resources