Skip to content

Fit

Interactive curve fitting for Linux, Windows and macOS

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-Voigt
T2BranchesPseudoVoigtPointsSet
yes——a single positiondiffraction.two-theta / diffraction.intensity
Asym. Pseudo-Voigt
TAsymPseudoVoigtPointsSet
yes——a single positiondiffraction.two-theta / diffraction.intensity
Constant background
TConstantBackgroundPointsSet
yes——a single position- / -
Doniach-Sunjic
TDoniachSunjicPointsSet
yes——a single positiondiffraction.two-theta / diffraction.intensity
Exponential background
TExponentialBackgroundPointsSet
yes——a single position- / -
Exponentially Modified Gaussian
TEmgPointsSet
yes——a single positiondiffraction.two-theta / diffraction.intensity
Gaussian
TGaussPointsSet
yes——a single positiondiffraction.two-theta / diffraction.intensity
Linear background
TLinearBackgroundPointsSet
yes——a single position- / -
Lorentzian
TLorentzPointsSet
yes——a single positiondiffraction.two-theta / diffraction.intensity
Moffat
TMoffatPointsSet
yes——a single positiondiffraction.two-theta / diffraction.intensity
Pearson VII
TPearson7PointsSet
yes——a single positiondiffraction.two-theta / diffraction.intensity
Power-law background
TPowerLawBackgroundPointsSet
yes——a single position- / -
Pseudo-Voigt
TPseudoVoigtPointsSet
yes——a single positiondiffraction.two-theta / diffraction.intensity
Quadratic background
TQuadraticBackgroundPointsSet
yes——a single position- / -
Skewed Gaussian
TSkewedGaussianPointsSet
yes——a single positiondiffraction.two-theta / diffraction.intensity
Step (erf)
TStepPointsSet
yes——a single positiondiffraction.two-theta / diffraction.intensity
User Defined
TUserPointsSet
yes——a single position- / -
Voigt
TVoigtPointsSet
yes——a single positiondiffraction.two-theta / diffraction.intensity

18 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 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 TConfigurableUserPointsSet["TConfigurableUserPointsSet"]
    class TConstantBackgroundPointsSet["TConstantBackgroundPointsSet"]
    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 TIntensityAxisMode["TIntensityAxisMode"]
    class TLinearBackgroundPointsSet["TLinearBackgroundPointsSet"]
    class TLorentzPointsSet["TLorentzPointsSet"]
    class TMoffatPointsSet["TMoffatPointsSet"]
    class TNamedPointsSet["TNamedPointsSet"]
    class TPearson7PointsSet["TPearson7PointsSet"]
    class TPointsSet["TPointsSet"]
    class TPolynomialBackgroundPointsSet["TPolynomialBackgroundPointsSet"]
    class TPowerLawBackgroundPointsSet["TPowerLawBackgroundPointsSet"]
    class TPseudoVoigtPointsSet["TPseudoVoigtPointsSet"]
    class TQuadraticBackgroundPointsSet["TQuadraticBackgroundPointsSet"]
    class TScientificModule["TScientificModule"]
    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 TVoigtPointsSet["TVoigtPointsSet"]
    TNamedPointsSet <|-- T2BranchesPseudoVoigtPointsSet
    TPseudoVoigtPointsSet <|-- TAsymPseudoVoigtPointsSet
    TSpecialCurveParameter <|-- TBackgroundCoefficientParameter
    TBackgroundCoefficientParameter <|-- TBackgroundLevelParameter
    TFormulaPointsSet <|-- TBackgroundPointsSet
    TConfigurablePointsSet <|-- TConfigurableUserPointsSet
    TPolynomialBackgroundPointsSet <|-- TConstantBackgroundPointsSet
    TTitlePointsSet <|-- 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
    TAxisMode <|-- TIntensityAxisMode
    TPolynomialBackgroundPointsSet <|-- TLinearBackgroundPointsSet
    TGaussPointsSet <|-- TLorentzPointsSet
    TFormulaPointsSet <|-- TMoffatPointsSet
    TCurvePointsSet <|-- TNamedPointsSet
    TFormulaPointsSet <|-- TPearson7PointsSet
    TSelfCopiedComponent <|-- TPointsSet
    TBackgroundPointsSet <|-- TPolynomialBackgroundPointsSet
    TBackgroundPointsSet <|-- TPowerLawBackgroundPointsSet
    TNamedPointsSet <|-- TPseudoVoigtPointsSet
    TPolynomialBackgroundPointsSet <|-- TQuadraticBackgroundPointsSet
    TObject <|-- TScientificModule
    TObject <|-- TScientificSession
    TObject <|-- TScientificValueStore
    TAxisMode <|-- TSinThetaOverLambdaAxisMode
    TFormulaPointsSet <|-- TSkewedGaussianPointsSet
    TFormulaPointsSet <|-- TStepPointsSet
    TAxisMode <|-- TThetaAxisMode
    TPointsSet <|-- TTitlePointsSet
    TAxisMode <|-- TTwoThetaAxisMode
    TObject <|-- TUserFormulaMenu
    TNamedPointsSet <|-- TUserPointsSet
    TFormulaPointsSet <|-- TVoigtPointsSet

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 TForm["TForm"]
    <<external>> TForm
    class TInterfacedObject["TInterfacedObject"]
    <<external>> TInterfacedObject
    class TNamedPointsSet["TNamedPointsSet"]
    <<external>> TNamedPointsSet
    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 TConfigurablePointsSet["TConfigurablePointsSet"]
    class TConfigurableUserPointsSet["TConfigurableUserPointsSet"]
    class TConstantBackgroundPointsSet["TConstantBackgroundPointsSet"]
    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 TInputBackFactorDlg["TInputBackFactorDlg"]
    class TInputWavelengthDlg["TInputWavelengthDlg"]
    class TIntensityAxisMode["TIntensityAxisMode"]
    class TLinearBackgroundPointsSet["TLinearBackgroundPointsSet"]
    class TLorentzPointsSet["TLorentzPointsSet"]
    class TMoffatPointsSet["TMoffatPointsSet"]
    class TNonConfigurablePointsSet["TNonConfigurablePointsSet"]
    class TPearson7PointsSet["TPearson7PointsSet"]
    class TPolynomialBackgroundPointsSet["TPolynomialBackgroundPointsSet"]
    class TPowerLawBackgroundPointsSet["TPowerLawBackgroundPointsSet"]
    class TPseudoVoigtPointsSet["TPseudoVoigtPointsSet"]
    class TQuadraticBackgroundPointsSet["TQuadraticBackgroundPointsSet"]
    class TResidualSpectrumView["TResidualSpectrumView"]
    class TScientificModule["TScientificModule"]
    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 TVoigtPointsSet["TVoigtPointsSet"]
    class TWavelengthDialogAdapter["TWavelengthDialogAdapter"]
    TNamedPointsSet <|-- T2BranchesPseudoVoigtPointsSet
    TPseudoVoigtPointsSet <|-- TAsymPseudoVoigtPointsSet
    TObject <|-- TBackFactorDialogAdapter
    TSpecialCurveParameter <|-- TBackgroundCoefficientParameter
    TBackgroundCoefficientParameter <|-- TBackgroundLevelParameter
    TFormulaPointsSet <|-- TBackgroundPointsSet
    TConfigurablePointsSet <|-- TConfigurableUserPointsSet
    TPolynomialBackgroundPointsSet <|-- TConstantBackgroundPointsSet
    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
    TForm <|-- TInputBackFactorDlg
    TForm <|-- TInputWavelengthDlg
    TAxisMode <|-- TIntensityAxisMode
    TPolynomialBackgroundPointsSet <|-- TLinearBackgroundPointsSet
    TGaussPointsSet <|-- TLorentzPointsSet
    TFormulaPointsSet <|-- TMoffatPointsSet
    TConfigurablePointsSet <|-- TNonConfigurablePointsSet
    TFormulaPointsSet <|-- TPearson7PointsSet
    TBackgroundPointsSet <|-- TPolynomialBackgroundPointsSet
    TBackgroundPointsSet <|-- TPowerLawBackgroundPointsSet
    TNamedPointsSet <|-- TPseudoVoigtPointsSet
    TPolynomialBackgroundPointsSet <|-- TQuadraticBackgroundPointsSet
    TObject <|-- TResidualSpectrumView
    TObject <|-- TScientificModule
    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
    TFormulaPointsSet <|-- TVoigtPointsSet
    TObject <|-- TWavelengthDialogAdapter

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.