Desperat søger cirkler

Figmas søgning efter den mystiske matematik bag iOS-formen

Dette er en historie om en Figma-ingeniørs jagt efter det perfekte svar på en programmeringsudfordring. Hvis det resonerer med dig, ansætter vi!

I et berømt interview fra 1972 svarede Charles Eames på en kort række af grundlæggende spørgsmål om designens art. Når han besvarede det første spørgsmål, definerede han design som "en plan for at arrangere elementer til at udføre et bestemt formål."

Hans andre svar er til tider korte, endda uhyggelige, men når han bliver spurgt om begrænsningens rolle i design, pausede han for at give det længste og mest overvejede svar i serien: ”Her er en af ​​de få effektive nøgler til designproblemet: designerens evne til at genkende så mange af begrænsningerne som muligt; hans vilje og entusiasme til at arbejde inden for disse begrænsninger. ”

Selvom jeg ikke er en designer efter erhvervslivet - jeg er en ingeniør, der arbejder på Figma, det webbaserede samarbejdsdesignværktøj - er det let at se, hvordan Eames 'bemærkninger også gælder for mit arbejde. I stedet for at arrangere UI-elementer til at fremstille produkter, arrangerer jeg matematiske koncepter udtrykt i kode for at implementere værktøjer og funktioner. Og begrænsninger for tid, enkelhed, vedligeholdelse og endda æstetik spiller en lignende dominerende rolle i min proces.

Et nyligt projekt fremhæver disse paralleller usædvanligt godt. Jeg fik til opgave på en eller anden måde at tilføje understøttelse af Apples sædvanligt navngivne 'squircle' form til Figma - med lidt andet at gå på, kom jeg til at arbejde med at undersøge.

Det, der udfoldede sig, var en matematisk odyssey, fyldt med falske starter, skjulte problemer, fremadskridende begrænsninger, udforskning, spænding og opløsning. Kort sagt, det var en historie, som enhver designer oplever i en vis skala næsten hver dag.

For at skabe glæde til matte nørder som mig og for at illustrere, hvordan designprocessen udfoldes, når matematik er mediet, præsenteres hvert trin nedenfor, fra firkant et til forsendelse.

Ringen: Glat operatør

Min historie begynder længe før jeg startede på Figma, den 10. juni 2013, den dag Apple frigav iOS 7. Der var noget subtilt ved opdateringen: startskærmens app-chiclets havde en saftigere, mere organisk fornemmelse. De er gået fra firkanter med afrundede hjørner til cirkel (et portmanteau af 'firkant' og 'cirkel').

Hvad er forskellen, spørger du? For at være retfærdig er det let - En cirkel begynder som den gamle afrundede firkant, men med noget sandpapir påført den del, hvor afrundingen begynder på hver side af hvert hjørne, så overgangen fra lige til buet er mindre pludselig.

At formulere dette ved hjælp af matematisk sprog er præcist: Krumningen af ​​en cirkelens omkreds er kontinuerlig, mens en afrundet firkant ikke er det. Dette kan virke trivielt, en sej historie, men ubevidst har det virkelig stor indflydelse: en cirkel ser ikke ud som en firkant med operation, der udføres; den registrerer sig som en enhed i sin egen ret, ligesom formen af ​​en glat sten i en vandløb, en samlet og elementær helhed.

1.1 - Afrundede firkanter mod cirkel: det er tilsyneladende de små ting!

I lang tid har industrielle designere, der fremstiller fysiske objekter, kendt, hvor vigtig krumning er for et objekts opfattelse. Prøv at kigge nøje på hjørnerne på en Macbook eller på en ældre skab med kabelføring under en skrivebordslampe. Bemærk, hvor svært det er at finde en retning, hvor hjørnerne har hårdt kontrasterende højdepunkter.

Dette er resultatet af krumningskontinuitet, og det er meget bevidst inkluderet i designet. Det er ingen overraskelse, at Apple med fingrene unikt i både de hårde og softwarepier til sidst krydsbestøvede deres interface-design med industrielle ideer ved at få deres ikoner til at se ud som de fysiske ting, de producerer.

Fra form til formel

Hos Figma elsker vi naturligvis iOS-designere, og vi føler, at vores brugere skal have de platformelementer, de har brug for lige ved hånden. For at give dem adgang til denne nye form under design, er vi nødt til at finde en præcis matematisk beskrivelse, så vi kan begynde at finde ud af, hvordan vi bygger den ind i vores værktøj.

Heldigvis har folk stillet dette spørgsmål, så længe iOS 7 har eksisteret, og vi er bestemt ikke den første til at gå denne del af rejsen! Grundlæggende indledende arbejde af Marc Edwards indeholdt et skærmbillede, der indikerede, at ikonformen var en særlig generalisering af en ellipse, kaldet en superellipse. Følgende matematiske formel kan beskrive cirkler, ellipser og superellipser afhængigt af hvordan a, b og n vælges:

2.1 - Superellipse-formel

Hvis du vælger, sig, n = 2, a = 5 og b = 3, får du en normal ellipse med en hovedakse på 5 orienteret langs x og en mindre akse på 4 orienteret langs y. At holde n = 2 og vælge a = b = 1 beskriver en perfekt enhedskreds. Hvis du vælger en værdi for n, der er større end to, er resultatet en superellipse - den afrundede elliptiske form begynder at smelte sammen i formen af ​​dens afgrænsende rektangel, hvor hjørnerne bliver perfekt skarpe i den grænse, som n går til uendelig. Tidlige forslag prøvede at beskrive Apples form med n = 5. Hvis du prøver det, ser du, at det ser virkelig tæt på, hvad du kunne finde på en enhed, der kører iOS 7+.

Hvis dette var den rigtige beskrivelse, kunne vi bare passe et rimeligt antal Bézier-segmenter til denne form og derefter udføre det delikate arbejde med at finde ud af, hvordan man integrerer dette nye koncept i Figma. Desværre viste en omhyggelig opfølgningsindsats, at superellipse-formlen ikke var helt rigtig (i dag bruges ægte superellipser som ikoner i andre sammenhænge). For alle valg af n i ligningen ovenfor er der faktisk en lille, men systematisk uoverensstemmelse sammenlignet med den ægte ikonform.

Dette er den første blinde gyde i historien: Vi har en elegant enkel ligning til noget, der ligner meget en iOS-cirkel, men det er fundamentalt forkert. Og vi skylder virkelig vores brugere den rigtige ting.

At gå foran kræver en vis alvorlig indsats, og igen er jeg glad for at høste, hvad andre har sået. En efterforsker, Mike Swanson fra Juicy Bits, lavede en hypotese, der bygger op cirklenes hjørner ved hjælp af en række Bézier-kurver, som han raffinerede ved hjælp af en genetisk algoritme for at optimere ligheden med den officielle Apple-form. De resultater, han opnåede, viste sig at være rigtige, hvilket er bevist med Manfred Schwinds fremragende direkte tilgang, der ser ret på iOS-koden, der genererer ikonerne. Så vi har to forskellige tilgange, der gav den samme Bézier-struktur: iOS 7 Squircles blev revnet og dobbelt kontrolleret af andre, og vi behøvede ikke engang at beregne noget!

En skruenøgle i værkerne

Der er stadig to vigtige detaljer, der forhindrer os i at klone formen direkte ind i Figma og gå videre:

For det første er der den overraskende kendsgerning, at iOS-versionen af ​​formlen (i det mindste på undersøgelsestidspunktet) viste sig at have nogle underlige egenskaber - hjørnerne er ikke nøjagtigt symmetriske, og den ene side har et minuscule lige segment, som helt klart ikke gør det. ' t hører til. Vi vil ikke have det, fordi det komplicerer både kode og test, men at fjerne det ekstra segment håndteres let ved blot at spejle den fejlfri halvdel af hjørnet.

For det andet, når man udjævner størrelsesforholdet på den rigtige iOS-rektangelform, ændres det pludseligt fra det cirkel, vi fokuserer på, til en helt anden form. Dette ville være ubehageligt for en designer og tager et stærkt synspunkt på, hvilke former 'skal' bruges under visse omstændigheder.

Den mest naturlige og nyttige opførsel, når man udflader en cirkel, er, at udjævningen gradvist forsvinder, indtil der ikke er plads til at “slibe” overgangen mellem det runde og de lige dele af hjørnet. Fladning endnu længere skulle reducere det afrundede sektions hjørneradius, hvilket er i tråd med, hvordan Figma opfører sig i dag. Apple squircle-formlen er til lidt hjælp for os her, fordi dens udjævning sker på en fast måde: den giver ingen indikation for, hvordan man kommer nærmere eller længere fra det gamle afrundede rektangel. Hvad vi virkelig har brug for er et parametriserbart udjævningsskema, hvor en bestemt værdi af parameteren svarer meget tæt til Apple-formen.

Som en ekstra bonus kan vi sandsynligvis anvende den samme proces på andre steder, hvor hjørneafrundring sker i Figma: som stjerner, polygoner og endda hjørner i vilkårlige vektornetværk, hvis vi kan parametrize udjævningsprocessen, der omdanner et afrundet firkant til en cirkel. med penværktøjet. På trods af komplikationen begynder dette at ligne en meget mere komplet og værdifuld funktion end blot at tilføje support til iOS 7-cirkler ville have været. Vi giver nu designere en uendelig række nye former til brug i mange situationer, og en af ​​dem svarer tilfældigvis til det cirkelformede ikonform, der fik os i gang i første omgang.

At kræve, at vores squircle-udjævningsplan kan justeres kontinuerligt, men alligevel overholder iOS 7-formen på et hvilket som helst behageligt punkt, er det justerbare interval den første nye begrænsning i vores historie, og det er svært at tilfredsstille. En analog opgave ville være for en danser at tage et enkelt stillbillede af en ballerina i midten af ​​flyvningen og derefter designe et spring på en sådan måde, at en film, hvor hun udfører det, gengiver billedet nøjagtigt på et præcist tidspunkt. Hvilket lyder freaking hårdt. Så måske er det nødvendigt med nogen beregning når alt kommer til alt?

Elværktøj: Differentialgeometri for plane kurver

Lad os tage et skridt tilbage og støv nogle formelle værktøjer, der hjælper os med at analysere, hvad der foregår, inden vi dykker ned i parametrisering af cirkler. Først og fremmest er vi nødt til at nøjes med, hvordan vi beskriver en cirkel. Når vi diskuterede superellipser før, brugte vi en ligning, der involverer x og y, hvor alle punkter (x, y) i planet, der tilfredsstiller ligningen implicit sporer superellipsen. Dette er elegant, når ligningen er enkel, men ægte cirkler er et lappeteppe af Bézier-kurver, der er splittet sammen, hvilket fører til uhåndterligt rodede implicit ligninger.

Vi kan håndtere denne komplikation ved at bruge en mere eksplicit tilgang: tage en enkelt variabel t, begræns den til et endeligt interval og kortlægge hver værdi, som t kan tage på dette interval, til et tydeligt punkt på cirkelomkretsen (Bézier-kurver er i sig selv næsten altid repræsenteret denne måde, faktisk). Hvis vi koncentrerer os om blot et af hjørnerne og derved begrænser vores analyse til en buet linje med en klar begyndelse og slutning, kan vi vælge kortlægningen mellem t og hjørnet, så t = 0 svarer til begyndelsen af ​​linjen, t = 1 svarer til enden af ​​linjen, og glider glat t mellem 0 til 1 glat sporer ud af den runde del af hjørnet. I matematisk sprog vil vi beskrive vores hjørne ved stien r (t), som er struktureret som

4.1 - Tilpasning af plankurve med [0,1]

hvor x (t) og y (t) er separate funktioner for t for x- og y-komponenterne i r. Vi kan tænke på r (t) som en slags stihistorie, sige til en tur, du ville tage i din bil. Hver gang t mellem, når du begynder, og når du ankommer, kan du evaluere r (t) for at få din bils position langs din rute. Fra stien r (t) kan vi differentiere for at få hastigheden v (t) og acceleration a (t):

4.2 - Plane kurvens hastighed og acceleration

Endelig kan den matematiske krumning, der spiller en hovedrolle i vores historie, igen udtrykkes med hensyn til hastighed og acceleration:

4.3 - Usigneret krumning af plane kurver

Men hvad betyder denne formel egentlig? Selvom det kan se lidt kompliceret ud, har krumningen en ligefrem geometrisk konstruktion, oprindeligt på grund af Cauchy:

  1. Centrum af krumning C på ethvert punkt P langs kurven ligger i skæringspunktet mellem linjen normal til kurven ved P og en anden normal linje taget uendeligt tæt på P. (Som sidebesked er cirklen centreret ved C som konstrueret ovenfor) kaldte den osculerende cirkel ved P, fra det latinske verb osculare, der betyder 'at kysse'. Er det ikke godt?)
  2. Krumningsradius R er afstanden mellem C og P.
  3. Krumningen κ er den inverse af R.

Som konstrueret ovenfor, er krumningen κ ikke-negativ og skelner ikke mellem højre og venstre vending. Da vi er interesseret i dette, danner vi den underskrevne krumning k fra κ ved at tildele et positivt tegn, hvis stien drejer til højre, og et negativt tegn, hvis stien drejer til venstre. Også dette koncept har en analog i billedet: på ethvert tidspunkt t er den underskrevne krumning k (t) bare den vinkel, som rattet er drejet igennem på tidspunktet t, med plustegn, der bruges til sving til højre og minus skilte til drejning til venstre.

Geometri er konge: parametrisering af buelængde

Når der er introduceret krumning, har vi et sidste par rynker til at stryge ud. Overvej først et øjeblik to biler, der kører ad en hjørneformet rute; den ene bil fortsætter med at fremskynde og bremser derefter hele vejen (), mens den anden bil hurtigt fremskynder og derefter kaster ned til slutningen. Disse to forskellige måder at køre på vil give meget forskellige stihistorier, selvom den nøjagtige samme rute blev taget. Vi bryder os kun om hjørnens form, ikke hvordan nogen chauffør forhandlede det - så hvordan kan vi adskille de to? Nøglen er at bruge ikke tid til at markere punkterne i historikken, men snarere den kumulerede afstand, der er tilbagelagt, eller lysbue. Så i stedet for at besvare spørgsmål som 'hvor var bilen ti minutter ind i sin tur?', Ville vi hellere svare 'hvor var bilen ti miles ind i sin tur?'. Denne måde at beskrive stier, buelængdeparametering, indfanger deres geometri alene.

Hvis vi har en vis stihistorie r (t) i hånden, kan vi altid udtrække buelængden s som en funktion af t fra stien ved at integrere dens hastighed som følger:

5.1 - Integreret buelængde

Hvis vi kan invertere dette forhold for at finde t (er), kan vi erstatte dette med t i vores stihistorik r (t) for at få den ønskede buelængdeparameterisering r (er). Parameterbue-længde af en sti svarer til en stihistorik lavet af en bil, der kører med enhedshastighed, så overraskende er hastigheden v (er) altid en enhedsvektor, og accelerationen a (r) er altid vinkelret på hastigheden. Følgelig forenkles buelængde-parametreret version af krumning til netop størrelsen af ​​acceleration,

5.2 - Krumning i parametriseringen af ​​buelængden

og vi kan klæbe på det passende højre- eller venstrehåndsskilt for at danne den underskrevne krumning k (er). Det meste af komplikationen i den mere generelle krumningsdefinition var åbenbart der bare for at annullere det ikke-geometriske indhold i stihistorikken. Krumning er trods alt en rent geometrisk mængde, så det er virkelig behageligt at se det se enkelt ud i den geometriske parameterisering.

Design krumningen, beregne kurven

Nu til den anden rynke: vi har lige set, hvordan man går fra en stihistorisk beskrivelse af en kurve r (t) til dens buelængdeparameterisering r (er), og hvordan man udtrækker den underskrevne kurvatur k (r) fra den . Men kan vi gøre det modsatte? Kan vi designe en krumningsprofil og udlede den fra forældrekurven? Lad os overveje bilanalogien igen - antag, at mens vi kørte med konstant enhedshastighed langs en rute, registrerede vi rattets position kontinuerligt under hele rejsen. Hvis vi tog de rattedata og gav dem senere til en anden chauffør, ville de være i stand til at rekonstruere ruten perfekt, så længe de spillede rattets positioner ordentligt og kørte nøjagtigt den samme hastighed. Så vi ser intuitivt, at vi har nok information til at rekonstruere forældrekurven, men hvordan ser beregningen matematisk ud? Det er lidt behåret, men det er stadig muligt takket være Euler ved hjælp af buelængdeparameteringen - hvis vi vælger et koordinatsystem, så kurven starter ved oprindelsen og har sin oprindelige retning retning langs x-aksen, så x (s) ) og y (e) kan rekonstrueres fra k (er) som følger:

6.1 - Gendannelse af en kurve fra dens krumning

Til sidst skal du bemærke argumentet for sinus- og kosinusfunktionerne ovenfor: det er integralet af den underskrevne krumning. Normalt er argumenterne, der leveres til trigonometriske funktioner, vinkler målt i radianer, og det viser sig også at være sandt i dette tilfælde: integralet fra a til b i den underskrevne krumning er overskriften ved b minus overskriften ved a. Så hvis vi starter med et kvadrat og sandet ud af hjørnet på en hvilken som helst skør måde, vi ønsker, så måler vi krumningen over den del, vi har slibet og integrerer resultatet, får vi altid π / 2.

Squircles under skalpellen

Nu hvor vi er rynkefri, så lad os se, hvad der sker, når vi anvender disse analyseværktøjer til nogle rigtige former. Vi starter med et hjørne af et afrundet rektangel, der har et hjørnets radius på et, hvor vi først tegner selve hjørnet og derefter krumningen som en funktion af lysbue-længden:

7.1 - Analyse af rundet rektangelkurvatur

Vi gentager denne proces nu, for at de rigtige Apple-squircle-hjørner ser på deres krumninger, som er meget anderledes og meget oplysende:

7.2 - iOS 7 squirkle-krumningsanalyse

Krumningen ser ganske ujævn ud, men det er ikke nødvendigvis dårligt. Som vi ser senere, er der en afveksling mellem at have en jævn krumningskurve og have et lille antal Bézier-kurver, og iOS-hjørnet bruger kun tre. Generelt vil designere hellere håndtere færre Bézier-kurver på bekostning af at have en matematisk perfekt krumningsprofil. Disse detaljer til side, kan vi slags skubbe til plotet til højre og se et generelt billede dukke op: krumningen ramper op, flater i midten og ramper derefter ned igen.

Gennembrud: Udjævning parametreret

Bingo! I den sidste observation ligger nøglen til, hvordan vi kan parametrere udjævningen af ​​vores cirkelhjørne. Ved nul udjævning ønsker vi en krumningsprofil som det afrundede rektangel: bordplade formet. Når udjævningen langsomt øges, ønsker vi, at bordpladen skal holde sig fast, mens dens klippekanter begynder at blive til stejle skråninger, hvilket giver en ensartet trapesformet krumningsprofil (stadig med et samlet areal på π / 2, selvfølgelig). Når udjævningen nærmer sig det maksimale, ønsker vi, at den flade del af trapezoidet forsvinder og efterlader os en bred trekantet profil med ensben, hvis tophøjde er den originale bordplade.

8.1 - Krumningsprofiler for forskellige værdier for udjævningsparameteren

Lad os prøve at udtrykke denne skitse af en krumningsprofil i matematiske termer ved hjælp af ξ som en udjævningsparameter, der varierer mellem nul og en. Forudgående brug med andre former, hvis hjørner ikke er rette vinkler, introducerer vi også vinklen θ som er hjørnens drejevinkel - π / 2 for firkanter. Ved at sammensætte begge dele kan vi definere en stykkevis funktion i tre dele, en til rampen op, en for den flade top og en til rampen ned:

8.2 - Parametering af krumningsprofilens parametre

Bemærk, at den første og tredje brik (ramperne) forsvinder, da ξ har en tendens til nul, og at det midterste stykke (den flade top) forsvinder, da ξ har en tendens til en. Vi viste ovenfor, hvordan vi kan gå fra en krumningsprofil til en forældrekurve, så lad os prøve det på den første ligning ovenfor, som beskriver en linje, hvis krumning starter på nul og støt stiger, når vi går langs den. Vi gør først det lette interiørintegral:

8.2 - Første integral af 6.1 som anvendt på ligninger 8.2

Fantastisk, indtil videre så god! Vi kan fortsætte med at chugge sammen for at danne det næste par integraler:

8.2 - Andet integral af 6.1 som anvendt på ligninger 8.2 (Fresnel-integral)

Desværre, her rammer vi et stød, da disse integraler ikke er lige så lette. Hvis du har hørt om forbindelsen mellem trigonometriske funktioner og eksponentialer, kan du gætte på, at disse integraler er relateret til fejlfunktionen, som ikke kan udtrykkes i form af elementære funktioner. Det samme gælder disse integraler. Så hvad gør vi? Det er uden for dette indlægs rækkevidde at retfærdiggøre (se dette matematisk udvekslingsindlæg for en anelse om, hvordan du ville gøre det), men i dette tilfælde kan vi i Taylor-udvidelserne erstatte sinus og kosinus og derefter skifte summen og integralen til opnå:

8.4 - Udvidelser af Fresnel-integrerede serier

Dette ser nærmest uigennemtrængelig i sin serieform, så lad os tage et skridt videre og udtrykkeligt skrive de første par termer i hver serie med al forenkling af multiplikation udført. Dette leverer de følgende få udtryk for formen x og y:

8.5 - Eksplicitte dele med lav ordre (n <3) på 8.3

Apotheose stofoid

Dette er et konkret resultat! Vi kan faktisk plotte dette par ligninger (givet nogle rimelige valg for ξ, θ og R) for at få en sti som en funktion af s. Hvis vi havde adgang til vilkårligt mange udtryk og kunne beregne summerne, ville vi se, at når s stiger, begynder kurven at spiral ind i sig selv, selvom dette sker langt fra det domæne, vi er interesseret i, hvilket er den fladere rampe -up sektion.

Når vi gentager en stemning fra et tidligere punkt i indlægget, er vi heller ikke de første til at træde her. På grund af sin lineære krumning, som er meget nyttig, har mange snublet over denne kurve i fortiden - det er kendt som en Euler-spiral, cornu eller en klutformet, og de finder meget brug i at designe spor til køretøjer, inklusive veje og rutsjebaner.

9.1 - Clothoid spiral op til s = 5

Ved hjælp af bare n <10-delen af ​​udvidelsen som angivet i 8.5 har vi endelig alle de nødvendige stykker til at gøre vores første artefakt. Udvidelsen repræsenterer den skrånende (første) del af ligning 8.2 - det er let at tilpasse den til den faldende (tredje) del, og vi vil bro disse skrånende dele med en cirkulær bue til den flade (anden) del. Denne metode leverer et matematisk perfekt cirkelhjørne, der nøjagtigt følger krumningsdesignet, vi først introducerede i ligninger 8.2. Her er krumningsanalysen udført for et klædeskablet hjørne med ξ = 0,4:

9.2 - Cirkelhjørne ved ξ = 0,4 ved brug af niende ordens klæbemidler og cirkulære buer

Selvom det føles godt at have opnået denne elegante form, må vi indse, at dette kun er en ideel version. Denne nøjagtige form fungerer ikke af flere grunde, hvoraf det første er det faktum, at cirkulærdelens krumningscenter bevæger sig som en funktion af udjævningsparameteren ξ - ideelt set ville den forblive fast.

Vigtigere er det, at lysbuenes styrke i de termer, vi har holdt for at fremstille plottene, kan være så høj som ni. I Figma skal kontinuerlige stier være repræsenterbare ved kubiske Bézier-kurver (hvoraf kvadratiske Bézier-kurver og linjer er specielle tilfælde), og dette begrænser os til kun at holde kubiske og lavere orden. Dette betyder, at serien ovenfor for x (r) og y (r) hver skal være afkortet til en enkelt betegnelse. Det er svært at have stor tillid til, at en sådan drastisk trunkering bevarer de egenskaber, vi kan lide.

Desværre er det ikke tilstrækkeligt at kassere vilkår med højere orden - den resulterende konstruktion fungerer meget dårligt, når ξ er stort. Vi kan se dette nedenfor i figuren tegnet for ξ = 0,9:

9.3— Cirkelhjørne ved ξ = 0,9 ved hjælp af tredje ordens klæbemidler og cirkulære buer

Denne form er klart ubrugelig. Det ser ud til, at tre ordrer ikke er nok til at holde krumningen stigende gennem rampen op og ned ad sektioner af parameteriseringen, hvilket betyder, at vi har et ton akkumuleret fejl, når vi kommer til cirkelsektionen. Desværre betyder dette, at alle vores stofformede resultater er ubrugelige, og vi er nødt til at vende tilbage til tegnebrættet.

Intet guld kan blive

Lad os tage et skridt tilbage, overveje vores begrænsninger igen og prøv at udtrække det, vi kan, fra de tidligere bestræbelser, inden vi går i en ny retning.

For det første ved vi, at den perfekte klutformede konstruktion har nøjagtigt den krumningsprofil, vi har brug for, men krumningscentret i det centrale cirkulære afsnit ændrer placering som funktion af udjævningsparameteren ξ. Dette er uønsket, fordi vores nuværende on-canvas rektangel afrunding UI bruger en prik lige i midten af ​​krumningen, som en bruger kan trække for at indstille hjørneradius. Det føles måske lidt underligt, hvis denne prik flyttede sig, efterhånden som udjævningen varierede. IOS-formens centrale sektion er også lige, hvor det ville være, hvis det kun var et afrundet rektangel, hvilket yderligere indebærer total uafhængighed af centrets placering fra ξ. Så vi kan holde det samme grundlæggende krumningsdesignmål og tilføje den begrænsning, at cirkelsektionen holder et fast krumningscenter, da ξ varierer.

For det andet ved vi, at designere ikke ønsker, at konstruktionen af ​​cirkelhjørnet skal være for kompliceret. Apples cirkel (efter at have fjernet den underlige lille lige del) har kun en Bézier-kurve, der forbinder dets cirkulære sektion med den indkommende kant, så måske kan vi konstruere den samme type ting?

For det tredje har vi en noget arkansk teknisk begrænsning, som ikke er synlig fra starten, men som bliver et stort implementeringsproblem. Lad os overveje et kvadrat, 100xx100px, der har afrunding af vaniljehjørner anvendt til et hjørneradius på 20px. Dette betyder, at hver side af firkantens omkreds har 60 px lige spor. Hvis vi flater kvadratet i et klemt rektangel, så det er 80px med 100px, vil den lige sektion af kortsiden kun være 40px lang. Hvad sker der, når vi fladt kvadratet så meget, at vi løber tør for et lige afsnit? Eller hvis vi udjævner det mere, så rektanglet er, f.eks. 20px med 100px? Figmas nuværende opførsel er at finde ud af den største værdi af hjørneafrunding, vi har plads til at anvende, og derefter tegne formen ved hjælp af den i stedet. Vores 20px med 100px rektangel ville således have 10px afrunding anvendt.

Hvis udjævning af hjørner med radius R og parameter ξ bruger p-pixels, skal funktionen p (R, ξ) være inverterbar til ξ (R, p).

Enhver udjævningsproces, vi måske bruger til at oprette en cirkel, spiser endnu mere af den lige kant end enkel afrunding gør. Forestil dig sagen ovenfor igen, et 100px med 100px-rektangel, anvende 20px afrunding, og anvend derefter en udjævningsprocedure, der fjerner yderligere 12 pixels fra de rette sider. Dette efterlader os et 36px-budget i det lige afsnit til udfladning. Hvad sker der, når du udjævner rektanglet til 60 px med 100 px? Det synes næsten åbenlyst, analogt, at vi skal støtte udjævningen, indtil budgettet er afbalanceret, og den lige del er nøjagtigt forbrugt. Men hvordan beregner vi værdien af ​​ξ, der tilfredsstiller et specifikt pixelforbrugsbudget? Vi skal kunne gøre dette hurtigt, ellers kan vi ikke implementere funktionen.

Igen har dette problem en meget præcis matematisk artikulering: Hvis udjævning af hjørner med radius R og parameter ξ bruger p-pixels, skal funktionen p (R, ξ) være inverterbar til ξ (R, p). Dette er en noget skjult begrænsning, som også ville have udelukket en høj-orden stofoid-løsning.

Endelig har vi en anvendelighedsbegrænsning, som er, at ændring af udjævningen faktisk skal gøre noget, der er synligt for formen. Hvis vi trækker udjævningsparameteren ξ frem og tilbage mellem nul og en, gør det bedre en synlig forskel! Forestil dig, at vi gjorde alt dette arbejde for noget, som folk næppe kan se - det er uacceptabelt. Dette er grundlæggende et krav om nyttighed, og som sådan er det åbenlyst den stærkeste begrænsning.

Hold det enkelt, cirkel

Lad os prøve det mest direkte, vi kan tænke på, som opfylder de begrænsninger, der er anført ovenfor, og prøv bare at vælge en enkelt parameteriseret Bézier-kurve, der tager den cirkulære del og knytter den op til den rette side. Figuren herunder viser en type Bézier-kurve, der er egnet til dette formål:

11.1 - Kubiske Bézier-kontrolpunkter for den opkørende del af cirklen

Et par af dens egenskaber fortjener yderligere forklaring. Først falder kontrolpunkterne 1, 2 og 3 alle i en linje. Dette sikrer, at krumningen ved punkt 1, der forbinder til den lige del af kredsen, er nøjagtigt nul. Generelt set, hvis vi definerer et koordinatsystem og forbinder punkt 1 med P1, punkt 2 med P2 osv., Er krumningen ved punkt 1 givet af:

11.2 - Uforenklet krumning ved punkt 1 fra figur 11.1

Vi kan betryggende se, at krydsproduktet forsvinder, når punkterne 1-3 er kollinære. Den samme formel kan anvendes på punkt 4 ved at mærke omvendt; at gøre det og tilslutte geometrien og etiketterne i figuren giver følgende for krumningen der:

11.3 - Forenklet krumning ved punkt 4 fra figur 11.1

Ideelt set ville dette være det samme som krumningsafsnittets krumning eller 1 / R, som giver os endnu en begrænsning. Endelig er værdierne for c og d fastgjort af det faktum, at slutningen af ​​denne kurve skal møde den cirkulære del og være tangent til den, hvor den går sammen, hvilket betyder, at krumningsbegrænsningen ovenfor bare giver os værdien af ​​b:

11.4 - Opløsning for b fra figur 11.1, som leverer krumningskontinuitet

Hvis vi finder det vigtigt at bevare den indledende lineære stigning i krumning (som den ideelle stofoidopløsning omtalt i punkt 1), kan vi indstille en lig med b, som fikserer alle punkterne på Bézier-kurven og giver os en potentiel løsning. Ved hjælp af disse observationer konstruerer vi en simpel Bézier-cirkel nedenfor ved hjælp af en udjævning på ξ = 0,6:

Dette ser temmelig godt ud, og det kræver en masse signaler fra den originale klutformede beregning. Desværre er variationen over det fulde interval fra ξ = 0 til 1 kun en meget subtil forskel i hjørneformen. Her viser vi hjørnet i to zoomniveauer med kurver for ξ = 0,1, 0,3, 0,5, 0,7 og 0,9 vist i forskellige farver:

Dette er en knap mærkbar effekt på trods af dens gode matematiske egenskaber. Det er bestemt tættere på at være et produkt end den kurve, vi fik ved at beskære den stofoid-serie, som vi overvejede tidligere. Hvis vi kun kunne finjustere formlen lidt for at få mere variation!

Små slag af kvæl

Vi kan tage endnu et lille skridt tilbage for at finde ud af, hvordan vi skal gå videre. Når vi husker, at vi har brug for et invertibelt forhold mellem pixels, der forbruges ved udjævning og udjævningsparameteren ξ, kan vi indledningsvis fokusere på denne kortlægning, gøre det så enkelt som muligt og se, hvad der kommer ud, når vi forsøger at foretage en parametrisering af cirkler fra det.

Vi ved allerede noget om, hvordan simpelthen afrunding af hjørnerne bruger pixels. Jeg går ikke gennem den nødvendige trigonometri, men at tage et hjørne af åbningsvinklen θ og afrunde det for at have en radius på R-pixels forbruger q-pixels i kanten fra hjørnets spids, med q givet som følger:

12.1 - Segmentlængde forbruges ved afrunding

Hvad hvis vi vælger p (R, ξ) baseret på q på bare den enklest mulige måde, noget som:

12.2 - Segmentlængde forbruges ved afrunding og udjævning

Alt dette betyder, at vores maksimale udjævningsindstilling igen forbruger længden på segmentet, som vi forbrugte ved afrunding normalt. At tage dette valg ville fastsætte mængden a + b fra figuren ovenfor. Husk, at c og d under alle omstændigheder er ordentligt faste, så at fastsætte a + b betyder, at der er en endelig beslutning at tage: hvor stor er en relativ til b? Igen, hvis vi tager det enkleste valg, nemlig a = b, har vi bestemt en anden modificeret Bézier-parameterisering, hvis hjørner og kurver vi viser nedenfor:

12.3 - Hjørneform og krumningsprofil til enkel udjævningsplan

Den visuelle variation ser lovende ud! Kurverne ser attraktive ud, slibede på en måde. Dog er krumningsprofilen temmelig grov. Hvis vi bare kunne gøre det lidt mindre stikkende, kan det være en alvorlig konkurrence for et produkt. På trods af den dårlige krumningsprofil har selv denne enkle form af familie et medlem, der ligner meget Apple-versionen af ​​cirklen, næsten tæt nok til at komme foran vores brugere uden dårlig samvittighed.

Nu henvender vi os til krumningsprofilen, vores sidste udestående problem. I stedet for at opdele forskellen jævnt mellem a og b, som vi gjorde ovenfor, hvorfor giver vi ikke to tredjedele af intervallet til a og den resterende tredjedel til b? Dette vil betjene krumningen fra at stige for hurtigt, reducere de lange haler på krumningsprofilen og skære ved piggene. Denne ændring resulterer i følgende former:

12.4 - Hjørneform og krumningsprofil for forbedret enkel udjævningsplan

Krumningsprofilerne er meget forbedrede, den visuelle variation i graden er stadig nok til, at dette er et nyttigt produkt, ξ = 0,6 næsten sømmer iOS-formen, og den fine visuelle karakter af kurverne, som denne forbløffende enkle tilgang genererer, bevares. Så vi må stille spørgsmålet - hvad blokerer det for at blive produktet? Ikke noget.

Ser på skibet sejle

Det er nyttigt her til sidst at reflektere over selve processen. Noget, som jeg gentager gentagne gange i denne historie, er kraften og effektiviteten ved at prøve den enklest mulige ting. Dette vil i værste fald give en grundlæggende sammenligning, hvis den enkleste ting ikke ender. Evaluering af det på en seriøs måde lyser også et lys over de vigtigste ting, vi skal overveje, når vi forbedrer fremgangsmåden og går videre. Og i de bedste tilfælde, som vores, sker den enkleste ting allerede ret godt!

Endelig er der en meditation om forskellen mellem et godt produkt og et perfekt. Jeg føler nogle lidelser af forlegenhed ved at skrive dette, at jeg ikke var i stand til at komme med en bedre krumningsprofil. Jeg er sikker på, at jeg kunne have givet mere tid - der er mange veje tilbage at udforske. Intellektuelt er det lidt utilfredsstillende at have fået et så smukt resultat som klutformede serien, men ikke i det mindste have været i stand til i det mindste at se en afspejling af det i den spline, vi sendte til sidst. Men der er også den bredere kontekst - tidsbegrænsningerne for at arbejde i et lille firma er meget reelle - og et design, der krænker disse, kan ikke betragtes som godt.