The period of a pendulum is calculated using the following formula:
We can rearrange the formula to calculate the length like this:
Note that the units in these formulas are meter and second, which is usually the case in physics. The constant g in this formula stands for the gravitational acceleration, and its value is 9.81 meters per square second. T stands for the period of the swing in seconds. This means the user needs to move the markers to two adjacent maximums and we need to calculate the time difference between these two maximums. Add the following method to the end of MeasurementViewController:
| private func periodFromMarkers() -> TimeInterval { |
| |
| guard let firstTimestamp = xAccelerationData.first?.timestamp, |
| let lastTimestamp = xAccelerationData.last?.timestamp else { |
| |
| return 0 |
| } |
| |
| let totalTime = lastTimestamp - firstTimestamp |
| let x1 = xDiagramView.lineOnePosition |
| let x2 = xDiagramView.lineTwoPosition |
| return TimeInterval(x2 - x1) * totalTime |
| } |
The marker positions are values between 0 and 1; they are fractions of the total recorded time. To determine the time difference between the marker positions, we need to multiply their difference by the total time frame of the recorded data.
Next, we need a method that calculates the length from the period using the formula from earlier.
Add the following code to the end of MeasurementViewController:
| private func lengthFrom(period: Double) -> Double { |
| return 9.81 * pow(period / (2 * Double.pi), 2) |
| } |
This is just the code representation of the formula for the length of the swing. The result is a Double value representing the length in meters.
With these two methods in place, we can finally calculate the length of the swing and show the result to the user. Add the following method to the end of MeasurementViewController:
| private func updateResultLabel() { |
| |
| let period = periodFromMarkers() |
| let length = lengthFrom(period: period) |
| |
| resultLabel.text = String(format: "Length: %.3lf m", length) |
| } |
This code uses the methods we’ve written to calculate the length of the swing and then updates the label with the result. We use a special initializer of String that allows us to format the resulting string. %.3lf tells the string that only three digits after the decimal point should be shown. We need to call this method whenever the value of a slider changes. Add the highlighted line of code to the end of sliderChanged(_:):
| @IBAction func sliderChanged(_ sender: UISlider) { |
| let value = CGFloat(sender.value) |
| if sender == lowerBoundSlider { |
| xDiagramView.lineOnePosition = value |
| yDiagramView.lineOnePosition = value |
| zDiagramView.lineOnePosition = value |
| } else if sender == upperBoundSlider { |
| xDiagramView.lineTwoPosition = value |
| yDiagramView.lineTwoPosition = value |
| zDiagramView.lineTwoPosition = value |
| } |
| |
» | updateResultLabel() |
Build and run the app on your iPhone and test it out. Find a playground and try to measure the length of the swing. Is the value you get plausible?
This is great. With just a few lines of code, we can now read sensor data from our iPhone and draw it on-screen. By adding the markers, we’ve transformed our iPhone into a measurement device as shown in the image.
With the techniques you’ve learned in this chapter, you can set your apps apart from many others in the App Store. You can make your apps respond to special gestures (like the one we added for the LogStore library in the appendix). By drawing on the view, you can build user interfaces that aren’t possible with the built-in elements. Think about how this could improve your future apps. But be careful to not go overboard with this. Also, keep in mind that some users might not be able to perform special gestures because of disabilities. Your user interface should always have elements that can perform the action connected to the special gesture without actually requiring the special gesture. Think of the special gestures as shortcuts for actions in your app.
18.218.169.50