December 94 - Exploring Advanced AOCE Templates Through Celestial Mechanics
Exploring Advanced AOCE Templates Through
Celestial Mechanics
Harry R. Chesley
PowerTalk provides AOCE catalogs to store and edit collections of information. The
Catalogs Extension to the Finder lets you use AOCE templates to extend the types of
information stored and the means of editing it, which makes the catalogs open-ended
rather than limited to the information types provided by Apple with the PowerTalk
software. This article explores several advanced features of AOCE templates, showing
how new types of entries can be added that store information about planets and
calculate their current locations and orbits.
The AOCE Catalogs Extension (CE) -- an extension to the Finder and one of the
PowerTalk components -- was originally conceived as an open-ended means of
providing addresses for PowerTalk mail and messaging; however, it goes well beyond
that original goal. The CE allows third-party developers to extend the Finder in a
variety of ways, including providing new catalog entry types, new views on the
contents of entries, new means of editing those contents, runtime calculation of
information to be displayed, and new actions to perform in the case of drag and drop
and double-click operations. AOCE templates, which serve as the extension mechanism,
provide resources and code that define the format, appearance, and functionality of
catalog entries.
Because this article explores advanced features of the AOCE template mechanism, we
assume some familiarity with AOCE catalogs and a basic understanding of AOCE
templates and the terms used to describe them. The article "Getting the Most out of
AOCE Catalog Records" in this issue gives an overview of AOCE catalogs and templates.
For in-depth information, the definitive reference is Inside Macintosh: AOCE
Application Interfaces.
In this article, we demonstrate how the template mechanism can be extended to plot
the orbits of the planets. For those of you who aren't interested in celestial mechanics
and could care less about the mathematics involved in calculating the position of a
celestial body, don't worry -- the article focuses on templates; you can skip the
details on celestial mechanics without limiting your understanding. But if you are
interested, see "Algorithms for Calculating Planetary Positions.
We begin by developing a set of templates that plot the positions and orbits of the
planets at a specified time. A sublist on one of the record information pages lists the
planets and their positions. We also develop templates to display information pages for
each planet; these pages enable the user to enter the information needed to calculate a
planet's orbit. The calculations and plotting are performed by code resources in the
templates. Using the techniques described in the article, you could add other types of
celestial bodies (such as comets, moons, and alien spacecraft) that would be defined by
a different set of parameters and have a different algorithm for calculating position
and orbit.
Although the templates are quite straightforward in general, the article focuses on
the code resources that implement three advanced features of the template mechanism:
• type conversion between text (RStrings) and custom, internal data
types -- to display and edit floating-point numbers and date/time information
• automatic calculation of property values when other selected property
values change -- to update the planet's position when the time or orbital
parameters change
• drawing in a custom view -- to display the plotted object positions and
orbits
DEFINING THE TEMPLATES
The templates we create define a record type of "hrc Orbits" to hold the list of planets
we want to display. The record contains an attribute type "hrc Planet" with one
attribute value per planet and an attribute value tag of 'plnt'. There's also a
single-valued attribute of type "hrc Orbits info," which holds information pertinent to
the orbits record.
Using an attribute value tag allows for future expansion to new types of objects --
spacecraft, for instance. In the example, the aspect template for the attribute type
"hrc Planet" is used only for attribute values with the attribute value tag 'plnt'. To add
a new type of object, which may require different orbital parameters and a different
algorithm to calculate the orbits, you would use a different tag. For example, an
attribute value that describes a spacecraft might have an attribute value tag of 'crft'.
We need to define the following templates:
• information page templates for the orbits record (record type "hrc
Orbits")
• information page templates for the attribute type "hrc Planets," which
is the attribute type of the sublist entries
• an aspect template for the record type "hrc Orbits
• an aspect template for the attribute type "hrc Planets
These templates are included on this issue's CD. There's nothing remarkable about
most of them. This article discusses only those portions of the templates that are more
interesting and unusual.
ORBITS RECORD INFORMATION PAGE TEMPLATES
We use two information pages to display the information stored in an orbits record
(Figure 1). The List information page contains a sublist of planets (attribute type
"hrc Planet"), allowing the user to create new planets and drag existing ones into and
out of the list. Besides an icon, name, and kind, the sublist on the List page displays x
and y coordinates for each planet. This is the location at the time given in the field at
the top of the page. The user can edit the time to see past and future positions. The
Continuous Update checkbox, when checked, causes the Time field to be constantly
updated to the current time. The state of this checkbox is kept in the "hrc Orbits info
attribute of the orbits record.
List
Plot
Figure 1. Information pages for the orbits record
The Plot information page contains a plot of the position of each planet in the sublist on
the List information page. When the Show Orbits checkbox is checked, the plot shows
not only the position of each planet, but also the future track -- the orbit -- of the
planet. Orbital calculations take a lot of time, especially on slower systems, so the
user can choose whether or not to display this information.
Listing 1 shows resource definitions for the Plot information page template. Note that
kOrbitsCustomViewProperty is used for the property number for both the Show Orbits
checkbox and the custom view that plots the positions. Normally two views don't share
the same property. Using the same one here causes an automatic redraw of the custom
view when the checkbox changes. This is simpler than using the code resource to
intercept the property-dirtied call resulting from the checkbox change and using a
dirty-property callback to cause the custom view to be redrawn. (Whenever a
property is changed, a kDETcmdPropertyDirtied call is made to the code resource.)
The bulk of the work for the custom view occurs in the code resource, as described
later in the section "Drawing in a Custom View.
Listing 1. Plot information page template
resource 'deti' (kOrbitsPlotPage, purgeable) {
2000, kDETNoSublistRect, noSelectFirstText,
{
kDETNoProperty, kDETNoProperty, kOrbitsPlotPage;
},
{}
};
resource 'rstr' (kOrbitsPlotPage+kDETTemplateName, purgeable) {
"hrc Orbits plot page
};
resource 'rstr' (kOrbitsPlotPage+kDETRecordType, purgeable) {
kOrbitsRecordType
};
resource 'rstr' (kOrbitsPlotPage+kDETInfoPageName, purgeable) {
"Plot
};
resource 'rstr' (kOrbitsPlotPage+kDETInfoPageMainViewAspect,
purgeable) {
"hrc Orbits main aspect
};
resource 'detv' (kOrbitsPlotPage, purgeable){
{
kDETSubpageIconRect, kDETNoFlags, kDETAspectMainBitmap,
Bitmap {kDETLargeIcon};
{12, kOrbitsPageWidth-120, 28, kOrbitsPageWidth-8},
kDETNoFlags, kOrbitsCustomViewProperty,
CheckBox {kPalatino, 12, kDETLeft, kDETBold,
"Show Orbits", kOrbitsCustomViewProperty};
{44, 8, kOrbitsPageHeight-8, kOrbitsPageWidth-8}, kDETNoFlags,
kDETNoProperty, Box {kDETUnused};
{47, 11, kOrbitsPageHeight-11, kOrbitsPageWidth-11}, kDETNoFlags,
kOrbitsCustomViewProperty, Custom {kDETUnused};
}
};
PLANET INFORMATION PAGE TEMPLATES
When the user double-clicks a planet in the sublist, a window opens with two more
information pages (Figure 2). The Orbit Calculation information page displays the
position of the planet at a user-specified time. The Orbit Parameters information page
displays, and lets the user enter, the values for the orbital parameters (shown earlier
in Table 1). These two pages could have been combined, but most users aren't
interested in seeing the orbital parameter values once they've been entered. They just
clutter up the interesting information -- the planet's location at a given time.
Orbit Calculation
Orbit Parameters
Figure 2. Information pages for a planet
ORBITS RECORD ASPECT TEMPLATE
We define one aspect template for the orbits record (record type "hrc Orbits") -- a
main aspect that also serves as the main view aspect for the orbits record information
pages. The aspect for the orbits record contains the properties listed in Table 2.
The kOrbitsNowProperty property and the entries in the sublist are stored in the
record, as specified by the 'dett' lookup table resource (shown below). You'll find the
full source code for the orbits record aspect template on this issue's CD.
resource 'dett' (kOrbitsMainAspect+kDETAspectLookup, purgeable) {
{
{kOrbitsAttributeType}, typeBinary,
useForInput, useForOutput, notInSublist, isNotAlias,
isNotRecordRef,
{
'long', kOrbitsNowProperty, 0;
};
{kPlanetAttributeType}, 'plnt',
notForInput, notForOutput, useInSublist, isNotAlias,
isNotRecordRef,
{};
}
};
ASPECT TEMPLATE FOR ATTRIBUTE TYPE "HRC PLANET
The aspect template for attribute type "hrc Planet" is also a main aspect template. The
properties defined by this aspect are shown in Table 3. The orbital parameters, as
well as the name of the attribute value (for example, "Mercury" or "Venus"), are
stored in the attribute value, so they're included in the 'dett' resource:
#define kExtendedPropertyType 2
#define kExtendedPropertyTypeSize 10
...
resource 'dett' (kPlanetMainAspect+kDETAspectLookup, purgeable) {
{
{kPlanetAttributeType}, 'plnt',
useForInput, useForOutput, notInSublist, isNotAlias,
isNotRecordRef,
{
'rstr', kDETAspectName, 0;
'btyp', kDETNoProperty, kExtendedPropertyType;
'blok', kTpProperty, kExtendedPropertyTypeSize;
'blok', kEpsilonProperty, kExtendedPropertyTypeSize;
'blok', kOmegaBarProperty, kExtendedPropertyTypeSize;
'blok', keProperty, kExtendedPropertyTypeSize;
'blok', kaProperty, kExtendedPropertyTypeSize;
};
}
};
Each of the properties in the 'dett' resource except kDETAspectName has a
template-defined custom property type of 2 (kExtendedPropertyType) and is 10
(kExtendedPropertyTypeSize) bytes in size. The actual format is that of the standard
SANE floating-point extended type. The 'btyp' element specifies that all subsequent
'blok' elements should produce properties of the type given (kExtendedPropertyType).
The 'blok' elements that follow specify a fixed-size block, kExtendedPropertyTypeSize
bytes in size. The next section describes how these property types get used.
As with the main aspect template for the orbits, the rest of this template is quite
simple and is included on the CD.
CUSTOM PROPERTY TYPE CONVERSION
The templates we're defining use two property types that aren't supported directly by
the CE: SANE floating-point extended, for orbital parameters and positions, and
date/time, for specifying the time for which the positions should be calculated. In
addition to using these property types for internal calculations, we want to display
them and let the user edit them. To do this, we display the items in text fields and
supply a code resource that translates between the internal representation of the
custom property types and text (RStrings). The code resource implements
convertToRString and convertFromRString when called by the CE. The part of the
Planet routine that figures out when to call the conversion functions is as follows:
#define kTimePropertyType 1
#define kTimePropertyTypeSize 8
pascal OSErr Planet(DETCallBlockPtr callBlockPtr)
{
if (callBlockPtr->protoCall.target.selector == kDETSelf)
switch (callBlockPtr->protoCall.reqFunction) {
...
case kDETcmdConvertToRString:
return convertToRString(callBlockPtr);
case kDETcmdConvertFromRString:
return convertFromRString(callBlockPtr);