How to add a curve type
A curve type is one unit. It subclasses TNamedPointsSet, answers a few questions about itself, and registers itself from its own initialization section. Nothing else is edited — the menu, the factory and the compatibility rules are all derived from what registered.
flowchart TB
unit["`**Your unit**
class(TNamedPointsSet)`"]
init["`**initialization**
RegisterCurveType(TYours)`"]
reg["`**TCurveTypesSingleton**
the curve factory`"]
menu["`**The Curve Type menu**
grouped by GetCurveTypeGroup`"]
engine["`**The engine**
instantiates by type id`"]
loss["`**Objective compatibility**
derived from AmplitudeIsUnbounded`"]
axis["`**Displayed axes**
preferred by PreferredAxisMode`"]
unit --> init --> reg
reg --> menu
reg --> engine
reg --> loss
reg --> axis
The questions a curve type answers
Each has a sensible default, so a type only overrides what differs. These are capabilities, not a list of type names: adding a type needs no edit to any compatibility table.
| Type | Analytic | Group | Unbounded amplitude | Placed by | Preferred axes |
|---|---|---|---|---|---|
2 br. Pseudo-VoigtT2BranchesPseudoVoigtPointsSet | yes | — | — | a single position | diffraction.two-theta / diffraction.intensity |
Asym. Pseudo-VoigtTAsymPseudoVoigtPointsSet | yes | — | — | a single position | diffraction.two-theta / diffraction.intensity |
Chebyshev backgroundTChebyshevBackgroundPointsSet | yes | — | — | a single position | - / - |
Constant backgroundTConstantBackgroundPointsSet | yes | — | — | a single position | - / - |
Doniach-SunjicTDoniachSunjicPointsSet | yes | — | — | a single position | diffraction.two-theta / diffraction.intensity |
Exponential backgroundTExponentialBackgroundPointsSet | yes | — | — | a single position | - / - |
Exponentially Modified GaussianTEmgPointsSet | yes | — | — | a single position | diffraction.two-theta / diffraction.intensity |
GaussianTGaussPointsSet | yes | — | — | a single position | diffraction.two-theta / diffraction.intensity |
Linear backgroundTLinearBackgroundPointsSet | yes | — | — | a single position | - / - |
LorentzianTLorentzPointsSet | yes | — | — | a single position | diffraction.two-theta / diffraction.intensity |
MoffatTMoffatPointsSet | yes | — | — | a single position | diffraction.two-theta / diffraction.intensity |
Pearson VIITPearson7PointsSet | yes | — | — | a single position | diffraction.two-theta / diffraction.intensity |
Power-law backgroundTPowerLawBackgroundPointsSet | yes | — | — | a single position | - / - |
Pseudo-VoigtTPseudoVoigtPointsSet | yes | — | — | a single position | diffraction.two-theta / diffraction.intensity |
Quadratic backgroundTQuadraticBackgroundPointsSet | yes | — | — | a single position | - / - |
Skewed GaussianTSkewedGaussianPointsSet | yes | — | — | a single position | diffraction.two-theta / diffraction.intensity |
Step (erf)TStepPointsSet | yes | — | — | a single position | diffraction.two-theta / diffraction.intensity |
User DefinedTUserPointsSet | yes | — | — | a single position | - / - |
VoigtTVoigtPointsSet | yes | — | — | a single position | diffraction.two-theta / diffraction.intensity |
19 curve types are registered in this build.
No registered type asks for a menu group, so the Group column is empty throughout. A type that returns a name from GetCurveTypeGroup gets a submenu of that name — which is what a pack contributing several related types wants, rather than crowding the flat list.
The curve classes
Read from the units themselves. A curve type is a point set first: TPointsSet holds the points, TCurvePointsSet adds the parameters a minimizer varies, and TNamedPointsSet adds the questions above. TCurveTypesSingleton is the registry every type registers into, and the three interfaces it implements are how the menu, the factory and the engine reach it — none of them names a curve class.
classDiagram
direction LR
class TAxisMode["TAxisMode"]
<<external>> TAxisMode
class TConfigurablePointsSet["TConfigurablePointsSet"]
<<external>> TConfigurablePointsSet
class TCoordinateAxis["TCoordinateAxis"]
<<external>> TCoordinateAxis
class TDataLoader["TDataLoader"]
<<external>> TDataLoader
class TInterfacedObject["TInterfacedObject"]
<<external>> TInterfacedObject
class TObject["TObject"]
<<external>> TObject
class TSelfCopiedComponent["TSelfCopiedComponent"]
<<external>> TSelfCopiedComponent
class TSpecialCurveParameter["TSpecialCurveParameter"]
<<external>> TSpecialCurveParameter
class ICurveFactory["ICurveFactory"]
<<interface>> ICurveFactory
class ICurveTypeIterator["ICurveTypeIterator"]
<<interface>> ICurveTypeIterator
class ICurveTypeParametersFactory["ICurveTypeParametersFactory"]
<<interface>> ICurveTypeParametersFactory
class ICurveTypeSelector["ICurveTypeSelector"]
<<interface>> ICurveTypeSelector
class ICurveTypeStorage["ICurveTypeStorage"]
<<interface>> ICurveTypeStorage
class IExpressionParser["IExpressionParser"]
<<interface>> IExpressionParser
class IUserCurveFormulaDlg["IUserCurveFormulaDlg"]
<<interface>> IUserCurveFormulaDlg
class IUserCurveRolesDlg["IUserCurveRolesDlg"]
<<interface>> IUserCurveRolesDlg
class T2BranchesPseudoVoigtPointsSet["T2BranchesPseudoVoigtPointsSet"]
class TAsymPseudoVoigtPointsSet["TAsymPseudoVoigtPointsSet"]
class TBackgroundCoefficientParameter["TBackgroundCoefficientParameter"]
class TBackgroundLevelParameter["TBackgroundLevelParameter"]
class TBackgroundPointsSet["TBackgroundPointsSet"]
class TChebyshevBackgroundPointsSet["TChebyshevBackgroundPointsSet"]
class TConfigurableUserPointsSet["TConfigurableUserPointsSet"]
class TConstantBackgroundPointsSet["TConstantBackgroundPointsSet"]
class TCountsNoiseRule["TCountsNoiseRule"]
class TCurvePointsSet["TCurvePointsSet"]
class TCurveTypeExplanationProvider["TCurveTypeExplanationProvider"]
class TCurveTypeParametersFactory["TCurveTypeParametersFactory"]
class TCurveTypeStorageAdapter["TCurveTypeStorageAdapter"]
class TCurveTypesSingleton["TCurveTypesSingleton"]
class TDiffractionAngleAxis["TDiffractionAngleAxis"]
class TDoniachSunjicPointsSet["TDoniachSunjicPointsSet"]
class TEmgPointsSet["TEmgPointsSet"]
class TExponentialBackgroundPointsSet["TExponentialBackgroundPointsSet"]
class TFormulaClassFinder["TFormulaClassFinder"]
class TFormulaPointsSet["TFormulaPointsSet"]
class TGaussPointsSet["TGaussPointsSet"]
class TGsasLoader["TGsasLoader"]
class TIntensityAxisMode["TIntensityAxisMode"]
class TLinearBackgroundPointsSet["TLinearBackgroundPointsSet"]
class TLorentzPointsSet["TLorentzPointsSet"]
class TMoffatPointsSet["TMoffatPointsSet"]
class TNamedPointsSet["TNamedPointsSet"]
class TNoiseRule["TNoiseRule"]
class TNoiseRuleExplanationProvider["TNoiseRuleExplanationProvider"]
class TPatternLoader["TPatternLoader"]
class TPearson7PointsSet["TPearson7PointsSet"]
class TPointsSet["TPointsSet"]
class TPolynomialBackgroundPointsSet["TPolynomialBackgroundPointsSet"]
class TPowderCifLoader["TPowderCifLoader"]
class TPowerLawBackgroundPointsSet["TPowerLawBackgroundPointsSet"]
class TPseudoVoigtPointsSet["TPseudoVoigtPointsSet"]
class TQuadraticBackgroundPointsSet["TQuadraticBackgroundPointsSet"]
class TSampledValues["TSampledValues"]
class TScientificModule["TScientificModule"]
class TScientificRulesUi["TScientificRulesUi"]
class TScientificSession["TScientificSession"]
class TScientificValueStore["TScientificValueStore"]
class TSinThetaOverLambdaAxisMode["TSinThetaOverLambdaAxisMode"]
class TSkewedGaussianPointsSet["TSkewedGaussianPointsSet"]
class TStepPointsSet["TStepPointsSet"]
class TThetaAxisMode["TThetaAxisMode"]
class TTitlePointsSet["TTitlePointsSet"]
class TTwoThetaAxisMode["TTwoThetaAxisMode"]
class TUserFormulaMenu["TUserFormulaMenu"]
class TUserPointsSet["TUserPointsSet"]
class TUxdLoader["TUxdLoader"]
class TVoigtPointsSet["TVoigtPointsSet"]
class TXrdmlLoader["TXrdmlLoader"]
TNamedPointsSet <|-- T2BranchesPseudoVoigtPointsSet
TPseudoVoigtPointsSet <|-- TAsymPseudoVoigtPointsSet
TSpecialCurveParameter <|-- TBackgroundCoefficientParameter
TBackgroundCoefficientParameter <|-- TBackgroundLevelParameter
TFormulaPointsSet <|-- TBackgroundPointsSet
TBackgroundPointsSet <|-- TChebyshevBackgroundPointsSet
TConfigurablePointsSet <|-- TConfigurableUserPointsSet
TPolynomialBackgroundPointsSet <|-- TConstantBackgroundPointsSet
TNoiseRule <|-- TCountsNoiseRule
TSampledValues <|-- TCurvePointsSet
TObject <|-- TCurveTypeExplanationProvider
TInterfacedObject <|-- TCurveTypeParametersFactory
ICurveTypeParametersFactory <|.. TCurveTypeParametersFactory
TInterfacedObject <|-- TCurveTypeStorageAdapter
ICurveTypeStorage <|.. TCurveTypeStorageAdapter
TInterfacedObject <|-- TCurveTypesSingleton
ICurveFactory <|.. TCurveTypesSingleton
ICurveTypeIterator <|.. TCurveTypesSingleton
ICurveTypeSelector <|.. TCurveTypesSingleton
TCoordinateAxis <|-- TDiffractionAngleAxis
TFormulaPointsSet <|-- TDoniachSunjicPointsSet
TFormulaPointsSet <|-- TEmgPointsSet
TBackgroundPointsSet <|-- TExponentialBackgroundPointsSet
TNamedPointsSet <|-- TFormulaPointsSet
TNamedPointsSet <|-- TGaussPointsSet
TPatternLoader <|-- TGsasLoader
TAxisMode <|-- TIntensityAxisMode
TPolynomialBackgroundPointsSet <|-- TLinearBackgroundPointsSet
TGaussPointsSet <|-- TLorentzPointsSet
TFormulaPointsSet <|-- TMoffatPointsSet
TCurvePointsSet <|-- TNamedPointsSet
TObject <|-- TNoiseRuleExplanationProvider
TDataLoader <|-- TPatternLoader
TFormulaPointsSet <|-- TPearson7PointsSet
TSampledValues <|-- TPointsSet
TBackgroundPointsSet <|-- TPolynomialBackgroundPointsSet
TPatternLoader <|-- TPowderCifLoader
TBackgroundPointsSet <|-- TPowerLawBackgroundPointsSet
TNamedPointsSet <|-- TPseudoVoigtPointsSet
TPolynomialBackgroundPointsSet <|-- TQuadraticBackgroundPointsSet
TSelfCopiedComponent <|-- TSampledValues
TObject <|-- TScientificModule
TObject <|-- TScientificRulesUi
TObject <|-- TScientificSession
TObject <|-- TScientificValueStore
TAxisMode <|-- TSinThetaOverLambdaAxisMode
TFormulaPointsSet <|-- TSkewedGaussianPointsSet
TFormulaPointsSet <|-- TStepPointsSet
TAxisMode <|-- TThetaAxisMode
TPointsSet <|-- TTitlePointsSet
TAxisMode <|-- TTwoThetaAxisMode
TObject <|-- TUserFormulaMenu
TNamedPointsSet <|-- TUserPointsSet
TPatternLoader <|-- TUxdLoader
TFormulaPointsSet <|-- TVoigtPointsSet
TPatternLoader <|-- TXrdmlLoader
Curve types the user defines
A type whose formula is typed at run time still arrives through the same registry. The configuration lives in a separate class (GetConfigurablePointsSet) rather than on the curve itself: these are class-level questions asked before any instance exists, and Free Pascal has neither multiple inheritance nor class methods in interfaces.
classDiagram
direction LR
class TAxisMode["TAxisMode"]
<<external>> TAxisMode
class TCoordinateAxis["TCoordinateAxis"]
<<external>> TCoordinateAxis
class TDataLoader["TDataLoader"]
<<external>> TDataLoader
class TForm["TForm"]
<<external>> TForm
class TInterfacedObject["TInterfacedObject"]
<<external>> TInterfacedObject
class TNamedPointsSet["TNamedPointsSet"]
<<external>> TNamedPointsSet
class TNoiseRule["TNoiseRule"]
<<external>> TNoiseRule
class TObject["TObject"]
<<external>> TObject
class TSpecialCurveParameter["TSpecialCurveParameter"]
<<external>> TSpecialCurveParameter
class ICurveTypeParametersFactory["ICurveTypeParametersFactory"]
<<interface>> ICurveTypeParametersFactory
class ICurveTypeStorage["ICurveTypeStorage"]
<<interface>> ICurveTypeStorage
class IExpressionParser["IExpressionParser"]
<<interface>> IExpressionParser
class IUserCurveFormulaDlg["IUserCurveFormulaDlg"]
<<interface>> IUserCurveFormulaDlg
class IUserCurveRolesDlg["IUserCurveRolesDlg"]
<<interface>> IUserCurveRolesDlg
class T2BranchesPseudoVoigtPointsSet["T2BranchesPseudoVoigtPointsSet"]
class TAsymPseudoVoigtPointsSet["TAsymPseudoVoigtPointsSet"]
class TBackFactorDialogAdapter["TBackFactorDialogAdapter"]
class TBackgroundCoefficientParameter["TBackgroundCoefficientParameter"]
class TBackgroundLevelParameter["TBackgroundLevelParameter"]
class TBackgroundPointsSet["TBackgroundPointsSet"]
class TChebyshevBackgroundPointsSet["TChebyshevBackgroundPointsSet"]
class TConfigurablePointsSet["TConfigurablePointsSet"]
class TConfigurableUserPointsSet["TConfigurableUserPointsSet"]
class TConstantBackgroundPointsSet["TConstantBackgroundPointsSet"]
class TCountsNoiseRule["TCountsNoiseRule"]
class TCreateUserPointsSetDlg["TCreateUserPointsSetDlg"]
class TCreateUserPointsSetDlgAdapter["TCreateUserPointsSetDlgAdapter"]
class TCurveTypeParametersFactory["TCurveTypeParametersFactory"]
class TCurveTypeStorageAdapter["TCurveTypeStorageAdapter"]
class TDiffractionAngleAxis["TDiffractionAngleAxis"]
class TDoniachSunjicPointsSet["TDoniachSunjicPointsSet"]
class TEmgPointsSet["TEmgPointsSet"]
class TExponentialBackgroundPointsSet["TExponentialBackgroundPointsSet"]
class TExpressionParserAdapter["TExpressionParserAdapter"]
class TFormulaClassFinder["TFormulaClassFinder"]
class TFormulaPointsSet["TFormulaPointsSet"]
class TGaussPointsSet["TGaussPointsSet"]
class TGsasLoader["TGsasLoader"]
class TInputBackFactorDlg["TInputBackFactorDlg"]
class TInputWavelengthDlg["TInputWavelengthDlg"]
class TIntensityAxisMode["TIntensityAxisMode"]
class TLinearBackgroundPointsSet["TLinearBackgroundPointsSet"]
class TLorentzPointsSet["TLorentzPointsSet"]
class TMoffatPointsSet["TMoffatPointsSet"]
class TNonConfigurablePointsSet["TNonConfigurablePointsSet"]
class TPatternLoader["TPatternLoader"]
class TPearson7PointsSet["TPearson7PointsSet"]
class TPolynomialBackgroundPointsSet["TPolynomialBackgroundPointsSet"]
class TPowderCifLoader["TPowderCifLoader"]
class TPowerLawBackgroundPointsSet["TPowerLawBackgroundPointsSet"]
class TPseudoVoigtPointsSet["TPseudoVoigtPointsSet"]
class TQuadraticBackgroundPointsSet["TQuadraticBackgroundPointsSet"]
class TResidualSpectrumView["TResidualSpectrumView"]
class TScientificModule["TScientificModule"]
class TScientificRulesUi["TScientificRulesUi"]
class TScientificSession["TScientificSession"]
class TScientificValueStore["TScientificValueStore"]
class TSinThetaOverLambdaAxisMode["TSinThetaOverLambdaAxisMode"]
class TSkewedGaussianPointsSet["TSkewedGaussianPointsSet"]
class TStepPointsSet["TStepPointsSet"]
class TThetaAxisMode["TThetaAxisMode"]
class TTwoThetaAxisMode["TTwoThetaAxisMode"]
class TUserCurveParameter["TUserCurveParameter"]
class TUserCurveRolesDlgAdapter["TUserCurveRolesDlgAdapter"]
class TUserFormulaMenu["TUserFormulaMenu"]
class TUserPointsSet["TUserPointsSet"]
class TUserPointsSetPropDlg["TUserPointsSetPropDlg"]
class TUxdLoader["TUxdLoader"]
class TVoigtPointsSet["TVoigtPointsSet"]
class TWavelengthDialogAdapter["TWavelengthDialogAdapter"]
class TXrdmlLoader["TXrdmlLoader"]
TNamedPointsSet <|-- T2BranchesPseudoVoigtPointsSet
TPseudoVoigtPointsSet <|-- TAsymPseudoVoigtPointsSet
TObject <|-- TBackFactorDialogAdapter
TSpecialCurveParameter <|-- TBackgroundCoefficientParameter
TBackgroundCoefficientParameter <|-- TBackgroundLevelParameter
TFormulaPointsSet <|-- TBackgroundPointsSet
TBackgroundPointsSet <|-- TChebyshevBackgroundPointsSet
TConfigurablePointsSet <|-- TConfigurableUserPointsSet
TPolynomialBackgroundPointsSet <|-- TConstantBackgroundPointsSet
TNoiseRule <|-- TCountsNoiseRule
TForm <|-- TCreateUserPointsSetDlg
TInterfacedObject <|-- TCreateUserPointsSetDlgAdapter
IUserCurveFormulaDlg <|.. TCreateUserPointsSetDlgAdapter
TInterfacedObject <|-- TCurveTypeParametersFactory
ICurveTypeParametersFactory <|.. TCurveTypeParametersFactory
TInterfacedObject <|-- TCurveTypeStorageAdapter
ICurveTypeStorage <|.. TCurveTypeStorageAdapter
TCoordinateAxis <|-- TDiffractionAngleAxis
TFormulaPointsSet <|-- TDoniachSunjicPointsSet
TFormulaPointsSet <|-- TEmgPointsSet
TBackgroundPointsSet <|-- TExponentialBackgroundPointsSet
TInterfacedObject <|-- TExpressionParserAdapter
IExpressionParser <|.. TExpressionParserAdapter
TNamedPointsSet <|-- TFormulaPointsSet
TNamedPointsSet <|-- TGaussPointsSet
TPatternLoader <|-- TGsasLoader
TForm <|-- TInputBackFactorDlg
TForm <|-- TInputWavelengthDlg
TAxisMode <|-- TIntensityAxisMode
TPolynomialBackgroundPointsSet <|-- TLinearBackgroundPointsSet
TGaussPointsSet <|-- TLorentzPointsSet
TFormulaPointsSet <|-- TMoffatPointsSet
TConfigurablePointsSet <|-- TNonConfigurablePointsSet
TDataLoader <|-- TPatternLoader
TFormulaPointsSet <|-- TPearson7PointsSet
TBackgroundPointsSet <|-- TPolynomialBackgroundPointsSet
TPatternLoader <|-- TPowderCifLoader
TBackgroundPointsSet <|-- TPowerLawBackgroundPointsSet
TNamedPointsSet <|-- TPseudoVoigtPointsSet
TPolynomialBackgroundPointsSet <|-- TQuadraticBackgroundPointsSet
TObject <|-- TResidualSpectrumView
TObject <|-- TScientificModule
TObject <|-- TScientificRulesUi
TObject <|-- TScientificSession
TObject <|-- TScientificValueStore
TAxisMode <|-- TSinThetaOverLambdaAxisMode
TFormulaPointsSet <|-- TSkewedGaussianPointsSet
TFormulaPointsSet <|-- TStepPointsSet
TAxisMode <|-- TThetaAxisMode
TAxisMode <|-- TTwoThetaAxisMode
TSpecialCurveParameter <|-- TUserCurveParameter
TInterfacedObject <|-- TUserCurveRolesDlgAdapter
IUserCurveRolesDlg <|.. TUserCurveRolesDlgAdapter
TObject <|-- TUserFormulaMenu
TNamedPointsSet <|-- TUserPointsSet
TForm <|-- TUserPointsSetPropDlg
TPatternLoader <|-- TUxdLoader
TFormulaPointsSet <|-- TVoigtPointsSet
TObject <|-- TWavelengthDialogAdapter
TPatternLoader <|-- TXrdmlLoader
Creating one is two dialogs, and every failure has a defined landing place — an unparseable formula reopens the first dialog rather than raising, and a cancelled setup leaves the type unselected instead of half-registered.
sequenceDiagram
autonumber
participant ui as TFormMain
participant iter as ICurveTypeIterator
participant conf as TConfigurableUserPointsSet
participant flow as RunUserCurveFlow
participant dlg as IUserCurveFormulaDlg
participant parser as IExpressionParser
participant factory as ICurveTypeParametersFactory
participant store as ICurveTypeStorage
participant roles as IUserCurveRolesDlg
ui->>iter: which registered type was clicked
iter-->>ui: GetCurrentCurveClass
ui->>conf: GetConfigurablePointsSet, HasConfigurableParameters
alt the type configures itself
ui->>conf: ShowConfigurationDialog
conf->>flow: the five collaborators, and nothing else
flow->>dlg: Ask - a name and a formula in x
alt cancelled
dlg-->>flow: daCancelled, and the definition is abandoned
else confirmed
flow->>parser: ParseExpression
alt the formula does not parse
parser-->>flow: nil, the message already shown
flow->>dlg: Ask again - nothing has been stored yet
else it parses
flow->>factory: CreateUserCurveType
flow->>store: AddCurveType
flow->>roles: Ask - which parameter plays which role
alt daAccepted
flow->>store: UpdateCurveType
else daStartAgain
flow->>store: DeleteCurveType, then Ask the formula again
else daCancelled
flow->>flow: the stored type is left as it is
end
end
end
end
alt configuration was cancelled and HasDefaults
ui->>conf: SetDefaults
else cancelled with no defaults
ui->>ui: say so, and leave the type unselected
end
Full instructions, including the traps: adding a curve model · writing a module · a complete working example.