Title Reprezentace slidu v paměti
Author Jiří Krutil
Date 15. 11. 1998
Reference jehne@kolej.mff.cuni.cz
File plpoint/docs/reprsld.html
Project Kolik třešní, tolik višní alias LeNoLin
Version 2

Popis reprezentace slidu v paměti

Reprezentace slidu v paměti v zásadě vychází z formátu, v jakém je slide uložen v souboru. Tyto dva formáty se poněkud liší tam, kde jsou v souboru použity párové tagy (tzn. u textového rámečku, bubliny a skupiny elementů).
U textového rámečku a bubliny tato odlišnost spočívá v tom, že text, který je v souboru mezi otevíracím a zavíracím tagem je v paměti uložen jako samostatný objekt, na který si textový rámeček uchovává ukazatel.
Rozdíl v reprezentaci skupiny prvků je podobný: místo otevíracího a uzavíracího tagu (které plní funkci "závorek") si skupina pamatuje prostě seznam ukazatelů na elementy, které do ní patří.

Obecný pohled

Slide je v paměti uložen jako stromová struktura objektů C++. Tyto objekty lze rozdělit do několika skupin:

Interface tříd

typedef struct _listelement {
  _listelement *next;
  void *data;
} listelement;

class List {
  listelement *first, *last, *actual;
  // *** methods ***
  create ();
  addfirst (void *data);
  addlast (void *data);
  void *takefirst ();
}

class KeyPoint:Point {
  idtype kpid;           // my ID
  Element *propertyof;   // element, that owns me
  unittype posx, posy;   // my position in the slide
  List ihold;            // list of the keypoints that I hold
  KeyPoint *attachedto;  // pointer to the keypoint that holds me
  // *** constructors ***
  KeyPoint (idtype id, Element *propertyof, unittype posx, unittype posy);
                         // constructor for normal keypoint or anchor
  KeyPoint (idtype id, Element *propertyof, KeyPoint *attachedto);
                         // constructor for floating key point
}

class Properties {
  colortype color, fillcolor;
  unittype thickness, radius;
  float splinex;
  zordertype zorder;
  booltype square;
  arrtype startarr, endarr;
  lttype typeofline;
  letype endsofline;
}

class Text {
  // format of the text contained here is specified elsewhere
}

class Element {
  idtype elid;           // my ID
  Properties properties; // my properties
  List anchors;          // my anchors
  // *** methods ***
  setcolor (colortype color);
  setfillcolor (colortype fillcolor);
  // ... and so on for all properties
  colortype getcolor ();
  colortype getfillcolor ();
  // ... also for all properties
  // and methods for all basic operations
}

class Slide:Element {
  unittype sizex, sizey;
  // *** methods ***
  create (Properties properties);
  show ();
}

class Group:Element {
  List icontain;            // list of the elements that I contain
  // *** methods ***
  create (List tobegrouped);
  ungroup ();
  // and set*, get* methods for all properties
}

class CutLine:Element {
  List keypoints;           // list of my keypoints
  // set*, get* methods for all properties
  refresh ();
}

class Rectangle:Element {
  KeyPoint (*keypoints)[4]; // my four corner keypoints
  // set*, get* methods for all properties
  refresh ();
}

class Ellipse:Rectangle {
  refresh ();
}

class Bubble:Rectangle {
  Text *text;               // text contained in this box
  KeyPoint (*keypoints)[5]; // my five keypoints
  // set*, get* methods for all properties
  refresh ();
}

Jak jste si možná všimli, chybí tady třída odpovídající mnohoúhelníku. Něco se tedy přece jen Kendymu podařilo prosadit (asi proto, že takhle to je lepší). Mnohoúhelník prostě chápeme jako speciální případ lomené čáry, který je dokonce vytvořen standardními prostředky: poslední klíčový bod lomené čáry je plovoucí a je ukotven do prvního klíčového bodu této čáry. Je-li lomená čára uzavřená (obsahuje-li "kružnici"), uzavřená oblast se vyplní. K tomu, aby byla lomená čára uzavřená, nemusí být nutně jeden její klíčový bod ukotven do druhého, ale stačí, se se někde na obrazovce protíná sama se sebou. Pokud je lomená čára neuzavřená, barva výplně se ignoruje.
V nové verzi jsem taky zrušil třídu TextBox. Používá se pouze Bubble a v případě, že je pátý klíčový bod odpovídající ukazující šipce nedefinován (NULL), jedná se o TextBox.
Novinkou je také univerzální seznam netypovaných ukazatelů, který se dá použít například k evidování prvků skupiny. Je-li potom potřeba se všemi prvky provést nějakou operaci, přetypují se ukazatele v seznamu na ukazatel na Element a zavolá se příslušná metoda, která je podle potřeby potomkem Elementu předefinovaná. Samotná skupina tedy ani neví, jakého typu jsou její prvky a ani to vědět nepotřebuje.
Všechny vlastnosti i seznam kotev se přestěhovaly do třídy Element a jsou děděny. V této třídě jsou také metody pro nastavení/zjištění hodnoty pro všechny vlastnosti, které jsou zde prázdné a každý potomek si ty, které používá, předefinuje. Metoda vracející hodnotu vlastnosti vrací implicitně nějakou hodnotu -1, která znamená, že danou vlastnost tento objekt nepoužívá (nemá pro něj význam). Toho se dá využít tehdy, když je označeno několik elementů a uživatel chce zobrazit nastavení jejich vlastností. V takovém případě se v polích dialogu zobrazí pouze ty hodnoty, které jsou pro všechny stejné (přesněji pro všechny, kteří je používají - a k tomu to právě slouží). Ostatní pole dialogu jsou prázdná a nastavením hodnoty do kteréhokoli pole se jednotně všem označeným elementům nastaví zadaná hodnota.
Do vlastností přibyla jedna reálná hodnota jménem splinex, která určuje "ostrost" ohybů slidu (přesné použití vysvětlí Králík).

Vztahy mezi objekty

Každá třída odpovídající nějakému elementu slidu je potomkem třídy Element. Třída Element obsahuje  ID elementu jednoznačné v rámci slidu a všechny základní metody, např: metodu pro zobrazení elementu, jeho posun, stranové převrácení, otočení, posun jeho klíčového bodu, zapsání do souboru apod. Tyto metody jsou prázdné a každý z potomků třídy Element si je předefinuje.
Díky tomu je možné, aby nebyly rozlišovány ukazatele na různé elementy podle jejich typu, ale používají se univerzální ukazatele typu *Element. Pokud by bylo někdy potřeba zjistit, na jaký konkrétní typ elementu vlastně ukazatel ukazuje, mohla by se do třídy Element přidat výčtová proměnná určující právě typ elementu.
Klíčové body a kotvy používají jiný přístup: existuje pro ně jediná univerzální třída KeyPoint, jejíž jedna instance může odpovídat buď normálnímu klíčovému bodu, kotvě, nebo plovoucímu klíčovému bodu. Záleží na tom, které proměnné se použijí a které ne.
Zde se ani nerozlišuje mezi pevným klíčovým bodem a kotvou - oba mají pozici, majitele a je možné k nim uchytit plouvoucí klíčové body. Toto rozlišení si uvědomuje pouze jejich majitel, který zná jejich význam a podle toho je používá.
Třída vlastnosti je používána podobným způsobem. Každý element má jednu statickou instanci této třídy a používá pouze ty vlastnosti, které využije.