Tuesday, July 02, 2019

Textual Representation of SwiftUI Paths

While on vacation, I've been creating my first Swift Package, for my incomplete Scalar2D project. While my major ambitions have been slow, it does have 2 useful features: it supports many ways to represent colors as strings, and it can generate 2D paths from standard SVG path element strings.

So you can write:
import SwiftUI
import Scalar2D_SwiftUI
import CoreGraphics

public struct TestFrogView : View {
    private let cgPath = CGPath.path(fromSVGPath: "M185 212C139 183 40 199 39 108A18 18 0 1 1 56 75Q67 53 91 45A18 18 0 1 1 127 38C170 29 193 62 220 161L225 110Q231 84 260 115C260 142 265 205 241 198Q215 193 227 230C236 249 161 249 125 248A5 5 325 1 0 122 259C192 264 248 249 237 226Q230 206 247 211  266 210 272 161C273 139 276 106 252 93 245 86 209 65 216 133 200 46 176 19 132 26A28 28 0 0 0 81 40Q61 46 52 63A27 28 0 0 0 27 110C33 192 70 192 145 205Z"
)!

    public var body: some View
    {
       GeometryReader
        {
           proxy in
            Path(self.cgPath.fitting(geometry: proxy)).strokedPath(StrokeStyle(lineWidth:3.0))
        }.frame(idealWidth:cgPath.boundingBoxOfPath.width, idealHeight:cgPath.boundingBoxOfPath.height)
    }
}

Scalar2D_SwiftUI package in action

One thing, I found out after putting the package together was that the SwiftUI path has a String representable form of its own. You can pass it a specially formatted string and it will generate a Path struct.

Thus, an SVG Path to make a heart in a circle:
"M 0 0 A 100 100 0 0 0 0 200 A 100 100 0 0 0 0 0 Z M0 45 C 63-23 171 87 0 200 C -171 87 -63 -23 0 45 Z"
Simple SVG of a Heart in a Circle
Can be represented by a SwiftUI Path representation of:
0 0 m  -55.2285 0 -100 44.7715 -100 100 c -100 155.228 -55.2285 200 -1.83697e-14 200 c  55.2285 200 100 155.228 100 100 c 100 44.7715 55.2285 0 6.12323e-15 0 c h 0 45 m 63 -23 171 87 0 200 c -171 87 -63 -23 0 45 c h 
Which is probably just a direct translation of the underlying CGPath, which does not have an explicit arc element, so the arcs that made up my circle—the "A" operands—got converted to the "c"  cubic Bezier operands. The stringRepresentation property on Path tends to add unneeded short line segments after moves, which is also probably an artifact of iterating through the CGPath to generate the text. 

You could use the included Path(string: String) constructor to generate text from shapes, but SVG paths have the advantage of being generated by common drawing applications, and having more features such as arcs, shortcut operands and relative coordinates. I'm not sure why Apple didn't choose SVG paths when deciding on a text format, but please give my Scalar2D Swift Package a try. 


Monday, March 04, 2019

Optimizing a TV Antenna with an HDHomerun

I get asked by users of my Signal GH iOS app for the HDHomerun network TV tuner what measurement they are supposed to improve as they adjust their TV antenna systems.  

The HDHomerun provides 3 metrics describing the data stream coming from the over the air antenna: 
  1. Signal Strength
  2. Signal to Noise (or Signal Quality)
  3. Symbol Quality
I've been thinking about the analogy of someone with a noisy hearing aid trying to understand someone talking in a noisy room. From this way of thinking, Signal Strength is either turning up the volume or moving closer to the talker. It's how loud the voice is to the listener. The problem with this is, that the signal might be too noisy or maybe you are boosting as much noise as signal, or making it so loud that it's painful. Some gain might be useful, but just ramping up the Signal Strength has its limits. 

In this analogy, Signal Quality is how noisy the voice is when it gets to the listener, if the hearing aid is high quality, or the room is naturally quality, even a fairly quiet talker can be understand. You might try buying a better aid which can add gain without adding additional noise, or move closer to the speaker. 

Finally, Symbol Quality is a measure of did you understand all the words the speaker said. If not, your understanding can be severely distorted. When it comes to digital TV, you either understand everything perfectly or the picture pixelates. So, when it comes to Symbol Quality you want 100% perfection, nothing else will do. This is why I show it as either a green filled circle ⬤ or a red ring  ⭕️ and don't bother to show the Symbol Quality number.

As you can see, I'm prodding you to understand that while some Signal Strength is necessary, and Symbol Quality perfection is mandatory, it is long term Signal Quality that you want to improve. This is why Signal GH graphs Signal Quality over time, and not the other two metrics. If you can get the Signal Quality consistently above, let's say, 80, this will lead to getting perfect Symbol Quality  so your job as an antenna system optimizer is to find out what steps it will take. 

In my case, several years ago, I went through the process of getting bigger and bigger quality UHF only antennas, on taller masts, using a quality UHF pre-amp, and using my Signal GH app to find just the right direction to point the antenna—actually I used more primitive tools in the beginning and it's what led me to develop Signal GH. With each step, signal quality for each of my local stations increased, and each would eventually have such consistently high signal quality that the Symbol Quality would pretty much never dip below 100% perfection. Initially, I pulled in 2-3 stations good enough to watch without pixelation, and now I have 8-9 with dozens of sub channels, including every major. It's a rare—and usually blustery day—when my picture breaks up. I have an advantage in that all the stations I'm interested in are in the same general direction, or are close by, so I didn't have to resort to exotic antenna configurations: just bigger and taller. 

One thing I like about networked TV tuners, like the HDHomerun, or the Tablo, is that since they are shared resources, I don't have to split my signal to every room in the house, instead, I split my antenna signal between an HDHomerun for live TV, and running my app; a Tablo for recording scheduled content; and my main TV for watching major sporting events, i.e. pro football. So, only split three ways. With a 3 way splitter, one of the splits gets twice the signal of the other two, and this output I connect to the Tablo, as it will be recording unattended. Minimizing splits is one way to get better signal quality. 

Another signal improving quality of networked tuners is shorter cable runs, as they can installed right next to the splitter. 


Here's a video I made to elaborate on signal metrics:





By the way, I occasionally hear from other Tablo users who own an HDHomerun solely to run Signal GH. Gratifying but I wish I could support the Tablo, but they don't appear interested in providing the data I would need. 

Friday, December 07, 2018

Changing My Mind and Buying a 2018 MacBook Pro 13"

In my last post I argued that you can get a perfectly useable used 2015 MacBook Pro development machine for half the cost of a moderately specced 2018 model. And, that is true. iOS development is relatively lightweight compared to video production. My work issued me a 2015 MacBook Pro 15" and I don't have any complaints.

But there is a difference between needs and wants.

The fact of the matter is that I've been doing OK financially. Even when I wasn't, I spent about $2400 in both 2004 and 1998 buying the computers with which I plied my trade. By that measure, the nearly $3000 I spent on a quad core, 16GB, 1 TB laptop is at worst par for the course. I can afford it.

And this little laptop is a pleasure. The screen is exceptional, the speakers are amazing, Touch ID is such a convenience. I haven't grown to like or use the Touch Bar, but on the other hand, I don't use tools that require the escape key, and it wasn't as if I could touch type the brightness control before.

It's fast. Having a quad core in this smaller form factor is a treat when it comes to Xcode builds.

Its battery lasts longer than I do.

Being able to charge from either side is surprisingly pleasing. I worry about the lack of MagSafe, but so far no incidents.

And that's mainly what I connect to this device: a single power cable. If it's at my desks this will include Ethernet and whatever connection is needed to drive my monitor. I have a 38" ultra wide display that a Thunderbolt 3 cable can drive at 60Hz. Nice. But mainly, I'm typing untethered on a couch or bed. There is no dongle hell for me as most of the time there is nothing to attach. Well, I do have to have a USB-C to lightning data cable on hand if I am debugging on an iPhone or iPad. I will say that keeping track of the various flavors of USB-C cables is a very non-Apple like experience, but  not a daily thing.

The keyboard is fine, accurate, fast even. Nothing attached to a laptop is going to match my clicky Das Keyboard for visceral enjoyment.  I've no preference between either the 2015 or the 2018 keyboards. (Oh, I see where the Touch Bar is suggesting the keyboard emoji 🎹. Cute.).

The trackpad could be smaller, and occasionally had been giving me false palm taps, but I guess an update fixed it. Regardless, it's the finest trackpad it's ever been my pleasure to use. I see co-workers haunting around the abominable Apple Magic Mouse instead of using the delightfully responsive and accurate trackpad in their MacBooks and I just don't understand.

So, yes. If you can afford it. If you have the cash—please don't go into debt for this luxury—the 2018 MacBook Pro is worth what Apple's charging for it.

Thursday, July 19, 2018

The 2018 MacBooks Pros are Out, Time to Buy a 2015 MacBook Pro Retina 13"

I've been concerned about how little time I spend on my home software projects these days, and have been thinking that maybe a MacBook Pro would allow me to quietly get some work done in the early hours when I wake up but don't want to wake my wife up with the noise of the mechanical keyboard and the beacon of light from the big monitor on my Mac Mini across the room. So, I was in the market for a new personal MacBook Pro, as the other portable Macs in the house are claimed by children.

The 2018 speed bump version of the Touch Bar MacBook Pros came out last week, so I diligently customized my dream machine: the 16GB, 1TB configuration of the new quad core  13".
$2,599.00

Which while a lot of money, would be fine as I do pretty well, and this would be a daily device, and I'd get a discount via my day job at a large corporation. Still it's a lot of money; and I just put a new roof on the house, and the children might want to go to college someday.

So, I browsed my company's used computer page, and found they were selling used 2015 MacBook Pros with Retina Display 8GB, 128GB.
$749

Now, I might be able to get along with 8GB as all I'm really doing is compiling small Swift projects, but 128GB would not even store my Xcode folder after all the simulators and whatnot are installed. Spending my days managing storage is not worth my time. This particular model takes a custom SSD, but it is easily replaceable. After getting scared off of a 3rd party SSD by the reviews on Amazon, I found a used 512GB OEM SSD on eBay.
+$438.88
$1,187.88

The two components arrived over the last couple days and I popped in the replacement drive—lost a case screw, ugh—did a clean install of High Sierra, installed my development tools on it. This is not going to be a video editor, a photo manager, or a repository of my iTunes content. I'll code and browse the web, and that's about it, not even the distraction of eMail. It's only a dual core, so it isn't going to compile as fast as the quad core in my 2012 Mac Mini, but it will drive my 38" ultra wide screen monitor (3840×1600) at 60Hz when docked unlike the 30Hz the Mini brings. Geekbench 4 gives it 3734 single, 7158 multi, so a bit faster at single than my Mini (3,382), a lot slower at multi (11,360); gotta love those old quad cores.

I setup the Mini to act as a Time Machine server, so the MacBook will be backed up automagically.

It has an escape key, not that I am one of those developers that use the escape key much, an SD reader, dual ThunderBolt 2 ports, and an HDMI port, so when attached to my desktop, it'll be pretty wired up with MagSafe, USB 3, DisplayPort and a Thunderbolt Ethernet adaptor. Not quite the simplicity of a single USB-C cable going into an eGPU I could have bought.

I lucked out with used. Its previous owner cared. You have to look closely at the MagSafe connector to even tell it's been used. It's spotless. The keyboard might not be my preferred mechanical, but has decent travel and doesn't have the poor reputation of subsequent models. The Retina display is flawless and beautiful. Not a True Tone with a P3 gamut, but a treat compared to the displays in my children's 2009 MacBook Pro and 2011 MacBook Air. Is compact and light so it won't be cumbersome using in bed, or slipping into my backpack with my corporate 15".  Just a beautiful machine. Still half the RAM, disk, and cores of the pricier new model, but a lot of ports, MagSafe, nicer keyboard, SD Card reader. A perfectly adequate app developer machine.

For less than half the money, I got more than half the machine.

Monday, July 16, 2018

Filing a Bug Against Core Graphics [Update: fixed]

So, I was verifying that my Chemistry Keyboard works with the iOS 12 beta, and I immediately noticed that the Globe button's icon looked like this:
As I render all my artwork with my own SVGgh library, I had stumbled across a bug in Core Graphics. After much checking and simplifying I figured out that it was possible to add an arc to a CGMutablePath with parameters such that a subsequent call to CGPathCloseSubpath would not maintain the path's current point, and instead revert it to (0.0, 0.0). 

Filed a bug (42266130) with the Apple bug reporter and I hope they can get around to fixing it by release. 

[Update: Fixed in the 5th beta. Thanks for the responsiveness.]

Tuesday, April 17, 2018

Good Artists Copy, Great Artists Steal


I'd like to take this quote apart and explain its meaning to me.

The general idea is someone develops an idea, something novel and interesting, and creates something new. Someone else,  the great artist, comes along becomes familiar with the original idea, groks it, realizes how to bring it to the next level, and is able to create a product that is so much better than the original creator, that the original is a forgotten footnote. At that point, the idea has been stolen by the great artist who understood the idea better than its creator.

Example, via my brother James, at one point opera was invented and its practitioners  busied themselves taking this interesting concept and making operas of varying quality, and everybody was pretty happy with what they were doing and congratulating themselves for creating this new art form. And straight out of Amadeus, Mozart came along and revealed what came before as primitive. Mozart took the basic idea of opera and made previous attempts obsolete.  He stole opera.

Example. Smart phones existed before the iPhone. The idea is pretty obvious, and Microsoft worked at cramming Windows into a handheld device and were happy enough being the leader in a niche market. Along came Steve Jobs and his team, they thought deeply about the idea of a handheld computer and came up with a design that revealed previous attempts as clumsy, ill thought out toys. They did not try to copy Microsoft by jamming OS X into a 3.5 inch screen. Instead, they stole the smart phone.

I asked—a really quite good—programmer and colleague, "Who invented the smart phone?" He told me "Apple".

The lesson to me is we should strive as creators not to just blindly iterate on each other's work, but to look for our moment, our flash of understanding when we too can steal an idea and make it our own. I'm still looking; someday.

Sunday, October 29, 2017

Why I'd Buy a Subaru Impreza over a Civic or a Mazda 3

As I've written before, I was fixated on buying a recent Mazda 3 hatchback. Such a beautiful car, available with my favored manual transmission. Zoom zoom. However, Mazda has been promising for years to support CarPlay, and I have stopped believing them.

So, I cast about for a hatchback, with CarPlay, and a manual transmission.

Well, what about the new Civic? I've driven the same Civic for 14 years; I like Honda. However, unless you include the pricey Type R model, Honda will not sell you a Civic with both a manual transmission and CarPlay. Plus, I think the current model is angularly ugly, filled with faux touches. Nor, do I like the added mechanical complexity of a turbocharger.

My co-worker who owns a 2017 Civic, loves it, and I understand why you need an automatic for the collision avoidance features.

I spent more time in the Edmunds app looking at cars, and on YouTube watching review videos. Seems as though most people say great things about the 2017 Subaru Impreza hatchback, which in its lowest trim, the 2.0i, has both CarPlay and a manual transmission. If you go up the trims, you will end  up with a larger screen, but I'm not going to spend thousands of dollars for a bigger screen. For once, the base model has everything I really want. And while the CVT transmission might give better gas mileage and have more safety features, nobody who reviewed the car said they liked the CVT, and I have to believe it will be less mechanically reliable than a manual. Plus, this will likely be my last gasoline burning car, and I want to enjoy the anachronism.

As a big plus,  all wheel drive is a great match for driving in New England.  I am already visualizing putting a couple of kayaks on the roof rack and heading out into nature with my family.

So, early in the new year, as soon as I muster up the cash, I intend to buy a used 2017 Impreza hatchback. Maybe.

CarPlay Drops? Try Shortening Your USB Cables

I have not been a happy CarPlay user for the last couple months. I'd started getting the occasional loss of connection with my previous 3rd party receiver, and it had just gotten worse when I switched in a new one. I'd connect my iPhone 5S, it would work for a few minutes, sometimes as long as half an hour, and then CarPlay would just disappear. Replugging it in would usually work, but typically for a shorter time. I'd taken to just listening to podcasts over Bluetooth.

Things I Tried

  1. Switching from a 3rd party Lightning cable to an Apple original.
  2. Putting the phone in low power mode (maybe it was a charging problem)
  3. Just using Podcasts, avoiding Maps or Phone.
  4. Turning off Bluetooth (I drove the half hour to work once without drops when I forgot my Apple Watch)
  5. Updating to the iOS 11.1 beta.

What Worked

Replacing the 40 inch Lightning cable with a 4 inch cable. The phone might have been hanging from the USB socket, but it didn't drop over several days of commuting. 

I had installed the receiver myself, and had purchased a cable with a USB-A male to flush mounted USB-A female. It looked nice, mounted on the dashboard, but 6 inches would have been as good or better than 6 feet.



A 6 foot USB Auto Cable
All, I really wanted, the flush mounted socket
To sum up the cable run: 
  • Cable embedded in receiver: 3Ft
  • Flush mounted cable: 6ft
  • Apple Lightning cable 3.5ft
So a bit over 12 feet. A quick googling indicates that USB 2 has a maximum length of between 3 and 5 meters (10-16 feet), so 12 was starting to be a bit marginal, coupled with 3 separate cables, my oldish phone, and I could see where it might not be reliable.

Long term solution

I pulled out the overlong cable and replaced it with a 3 foot version. Fingers crossed; I've fooled myself into thinking I'd solved this a couple times before.