Een (WYSIWYG) wiskunde editor (1)


Inleiding

In dit artikel beschrijf ik de opzet van een wiskunde editor.
Daarbij wordt geen gebruik gemaakt van een script:
tekst elementen worden direct vanuit menu's geselecteerd en tekst wordt direct ingetikt.
Daarmee is het een zogenaamde WYSIWYG (What You See Is What You Get) type editor.

Het gehele editor project heeft de volgende onderdelen:
    – tekst: machten, indices, breuken, wortels ...
    – tekenen: punten, lijnen, cirkels, vlakken...
    – meetkundige constructies: middelloodlijnen, in- en omgeschreven cirkels...
    – grafieken van vergelijkingen en functies
Dit artikel is een introductie tot het tekst gedeelte.
De beschrijving is op blokdiagram niveau, onafhankelijk van een bepaalde programmeertaal.

Eerst een paar voorbeelden


Links is eerst y=2 ingetikt en daarachter is een paar haakjes met lijn element geplaatst.
Lege, nog in te vullen lijnen, worden met de kleur geel aangegeven.
Op de lege lijn wordt x-1 getikt, daarna wordt achter de x een macht element geplaatst.
We zien dat de haakjes hun positie en hoogte automatisch aanpassen.

Rechts is y= ingetikt en daarachter is een breuk element geplaatst.
In de teller tikken we 1 en in de noemer 3x-7.
Dan plaatsen we een macht element achter de x en tikken een 2 om x te kwadrateren.
We zien dat de teller wordt gecentreerd en dat de noemer zijn vertikale positie aanpast om de breukstreep
met y= uit te lijnen.

Nog een voorbeeld:
Eerst is y= ingetikt met daarachter een wortel element.
In de lijn onder het wortelteken tikken we 1+ en plaatsen een breuk element.
In dit breuk element tikken we 1 (teller) en x+1 (noemer).

Dan vervangen we de x door een breuk element en tikken weer 1 (teller) en (x+1) noemer.

We zien dat het wortelteken zich aanpast en dat de breuken uitlijnen.

De opzet

De tekst bestaat uit elementen, die op het document worden geplaatst.
Een element wordt vastgelegd met getallen. Daarmee wordt het beeld (pixels) berekend.
Elementen zijn rechthoekig van vorm.
Er zijn de volgende typen elementen:
    - tekens: letters, cijfers, griekse letters, speciale tekens...
    – lijnen
    – macro's : machten, indices, breuken, wortels, sigma, integraal...
    – blokken : die kunnen behalve tekst ook afbeeldingen, grafieken of tabellen bevatten
De tekens zijn van het "XFont" type, een zelf ontwikkeld font met o.a. de volgende eigenschappen:
    - ook Griekse letters
    - speciale tekens voor meetkundige bewijzen en verzamelingen
    - uitlijning van + - en = tekens
    - vaste breedte van cijfers voor correcte uitlijning
Macro's bevatten één of meer lijnen en soms grafische elementen zoals breukstrepen of worteltekens.
Lijnen kunnen tekens en macro's bevatten.
De structuren kunnen erg complex worden en daarom is een consequente organisatie noodzakelijk.
Er is gekozen voor een abstracte aanpak.

Een element moet:
    1. zichzelf kunnen tekenen.
    2. zijn eigen afmetingen kunnen berekenen.
    3. de positie berekenen van de elementen die er binnen liggen
Een element bepaalt dus nooit zijn eigen positie.

Een element is daarmee een soort black box : van buitenaf gezien zijn alleen van belang:
    - de afmetingen
    - de base line (straks meer daarover)
Alle andere eigenschappen zijn alleen van toepassing voor de handelingen die het element zelf moet verrichten.

Edit functies, zoals invoegen of verwijderen van elementen zijn abstract:
het maakt niet uit welk type element het betreft: teken, macro of lijn.

Het character (teken) element


Onderstaand plaatje toont een lijn met twee characters.
De characters zijn de children van de lijn. De lijn is de parent van de characters.
De parent bepaalt de positie (x,y) van zijn children ten opzichte van zichzelf.



Een lijn heeft een zg. base. Ook characters en macro's hebben een base.
Een lijn plaatst zijn children met hun base op de eigen base. Dat geeft uitlijning in vertikale zin.
De lijn schuift verder zijn children links aan en berekent daarna zijn lengte en hoogte.

Het voordeel van deze codering is dat verplaatsing van een element geen invloed heeft op de children.

Macro's

De toevoeging van macro's maakt van deze editor een wiskunde editor.
Hieronder staat het keuze menu voor macro's (tot dusver, meer zijn in ontwikkeling)



Een macro heeft één of meer lijnen als child en bevat soms ook een paar grafische symbolen
zoals een wortelteken of breukstreep.
Die grafische symbolen worden nergens gecodeerd maar pas berekend als het element zichzelf tekent.

De in te vullen lijnen van elke macro zijn met een licht gele kleur en een rood randje aangegeven.

Een paar macro's hebben extra keuzes, te zien aan een rood driehoekje.
Met een rechter muisklik wordt een menu uitgevouwen:
Nog een voorbeeld: de ABC formule ax² + bx + c = 0 heeft als oplossingen



Na de x is een indices macro toegevoegd voor de 1,2 ,
na het = teken komt een breuk met na de +/- een wortel macro en na de b een macht macro.
Nergens hoefde ik rekening te houden met de uitlijning. Dat ging vanzelf.

Parent en Children

Een parent kan een hele ris children hebben.
Een parent verwijst zelf naar het eerste kind, elk kind verwijst naar het volgende met next
en naar het vorige met previous.

Parent, child, next en previous zijn element nummers en leggen de onderlinge samenhang vast.

De eigenschappen van een element zijn gecodeerd in een record (type Telement).
Het hele document is een array van deze Telement records.
Parent,child,next en previous vormen ook een record van het type TLink.
Per element is er zo'n record in array links.

Hieronder staat de structuur:



Er is geen rechtstreekse toegang tot het links[..] array.
Wijziging van links[ ] kan alleen indirect via procedures.
Ook is hieraan het UNDO systeem gekoppeld. Maar dat is weer een ander verhaal.
Edit handelingen komen neer op wijzigen in array links[..] als het betreft invoegen,
toevoegen of verwijderen van elementen.
Wijzigingen aan fonts of styles vinden plaats in het elements[..] array.

De velden elType,elCode,p1 en p2 zijn van het type byte, de overige van het type word.
De betekenis van p1,p2 en p3 is element afhankelijk.
Meestal is p1 het font (verwijzing in tabel), p3 is de baseline positie.

In Links zijn de velden van het type dword (32 bit unsigned integer).

Element 1 is het gehele document. Dit element heeft als enige geen parent.
Alle overige elementen zijn children (van children, van children...) van element 1.

Als een element verandert dan wordt daarna de parent gevraagd zichzelf opnieuw te berekenen.
Dat houdt dus ook herberekening in van de positie van de children.
Als tengevolge van deze berekening de afmetingen van de parent wijzigen, dan roept deze
ook zijn parent aan. Enzovoorts.

Nog een voorbeeld, dat in een paar seconden is gemaakt:





Hier zie je de boomstructuur


Een laatste voorbeeld:



Naschrift

Het is minstens 15 jaar geleden dat ik het plan opvatte een wiskunde editor te ontwerpen.
De meeste ontwerpen zijn in de prullenbak beland.
Maar de hier beschreven structuur is veelbelovend.
Het principe is niet zo moeilijk, maar door de abstracte aard zijn sommige procedures lastig.
Er is nog veel werk te verzetten om de editor gebruikersvriendelijk te maken.

In een volgend artikel wellicht meer over de uitwerking.