;;########################################################################
;; mdsmob2.lsp
;; Multidimensional Scaling, Part 2
;; Copyright (c) 1991, 92 by Mary M. McFarlane
;; Written   by Mary McFarlane & Chris Wiesen, September, 1991
;; Rewritten by Mary McFarlane, February, 1992
;;########################################################################

(require "vista")

(defmeth cmds-model :visualize ()
  (if (not (eq current-object self)) (setcm self))
  (let* ((spread (spread-plot 
                  (matrix '(2 3) 
                          (list (send self :mds-3d-scatterplot)
                                (send self :mds-3d-spin-plot)
                                (send self :name-plot)
                                (send self :mds-2d-plot)
                                (send self :scree-plot)
                                (send self :mds-stress-plot)
                                ))))
         )
    (send spread :show-spreadplot)
    
    (defmeth spread :spreadplot-help ()
      (plot-help-window (strcat "SpreadPlot Help"))
      (paste-plot-help (format nil "This is the SpreadPlot for Multidimensional Scaling. In this SpreadPlot the windows are linked by the data's stimuli (rows and columns of the data matrix) and by the dimensions of the MDS model. They are also linked via the equations of the MDS model.~2%"))
      (paste-plot-help (format nil "The Scatterplot Matrix window, which is in the upper left corner, lets you choose which MDS dimensions are displayed in other windows. You can select two dimensions by clicking on an off-diagonal cell. You can also select several dimensions by shift-clicking on several cells.~2%"))
(paste-plot-help (format nil "The Stimuli window, at the upper right, presents labels for the stimuli (the rows and columns of the data matrix). Selecting labels will cause points and vectors in the other plots to be highlighted.~2%"))
      (paste-plot-help (format nil
"The points in the windows of this spreadplot are linked together. When you brush or click on them in one window, the corresponding points or vectors in other windows are also highlighted. The points are linked together because they represent the same row and column of your data. By looking for the structure revealed in each window you can get a better understanding of your data.~2%"))
      (paste-plot-help (format nil "The windows are also linked algebraically through the Drag Point mouse mode of the Stimulus Plane window. When the mouse is in this mode, points can be moved to new locations. When a point is moved, the model recalculates itself and presents the new results graphically.~2%"))
      (show-plot-help)
      (call-next-method :skip t :flush nil))
    
    t))

(defmeth cmds-model :mds-stress-plot (&optional (stream t))
  (let ((num-dims (send self :number-dimensions))
        (num-mats (length (send self :matrices-numbers)))
        )
  (if (not (eq current-object self)) (setcm self))
  (setf stressp (plot-points (list 1) 
                             (list (send self :stress))
                             :show nil
                             :title "Stress Plot"
                             :variable-labels (list "Iteration" "Stress")))
  (send stressp :margin 0 17 0 0)
  (send stressp :add-overlay (send vista-graph-overlay-proto 
                :new :mouse-mode nil :new-x nil :new-y nil))
  (send stressp :showing-labels t)
  (send stressp :point-label 0 
        (format nil "~5,4f" (send stressp :point-coordinate 1 0)))
  (send stressp :point-state 0 'selected)
  (send stressp :use-color t)
  (send stressp :point-color 0 'red)
  (send stressp :mouse-mode 'brushing)
  (send stressp :range 0 0 5)
  (send stressp :x-axis t t 6)
  (send stressp :menu nil)
  (defmeth stressp :redraw ()
    (let* ((maxy (max (send stressp :point-coordinate 1 
                            (iseq (send stressp :num-points)))))
           (gnrx nil)
           )
      (when (> (send self :num-points) (second (send self :range 0)))
            (setf gnrx 
                  (get-nice-range 0 (+ 5 (second (send self :range 0))) 5))
            (send self :range 0 (first gnrx) (second gnrx) :draw nil)
            (send self :x-axis t t (third gnrx) :draw nil))
      (send stressp :range 1 0  (* .1 (ceiling (* 10 maxy))) :draw nil)
      (send stressp :y-axis t t (1+   (ceiling (* 10 maxy))) :draw nil)
      (call-next-method)))
  (defmeth stressp :plot-help ()
      (plot-help-window (strcat "Help for " (send self :title)))
      (paste-plot-help (format nil "The Stress plot shows the fit of the multidimensional scaling model to the dissimilarity data."))
    (when (> num-mats 1)
          (paste-plot-help (format nil " Since there are ~d matrices of data, the fit is to the root-mean-squared data matrix."num-mats)))
    (paste-plot-help (format nil " The fit is shown for a ~d-dimensional model, since this is the dimensionality you specified. The fit is shown for each iteration. Initially, there is just one value shown.~2%" num-dims))

(if (= 1 (send stressp :num-points))
    (paste-plot-help (format nil "Currently, the fit is shown for just the initial solution. You can start the iterative process by clicking on the ITERATE button in the STIMULUS SPACE window~2%"))
    (paste-plot-help (format nil "Currently, the fit is shown for ~d iterations. Additional iterations can be performed by clicking on the ITER button in the STIMULUS SPACE window.~2%"(send stressp :num-points))))

    (paste-plot-help (format nil "The Stress plot is used to help you decide whether more iterations are needed to obtain a stable solution. As the iterations proceed, the positions of the stimulus points, as shown in the STIMULUS PLANE MATRIX, STIMULUS SPACE and STIMULUS PLANE plots, become stable, and the Stress value declines slowly, if at all. When this happens, the iterative process has converged on a stable solution, which is ready for interpretation.~2%"))
    (paste-plot-help (format nil "Unfortunately, it is not possible to say what value of Stress represents a good fit. It is known that Stress is effected artifactually by the number of stimuli and the number of dimensions, making it essentially impossible to say whether a particular value is good or bad. You must rely instead on whether the stimulus space, as shown in the STIMULUS PLANE MATRIX, STIMULUS SPACE and STIMULUS PLANE plots, is interpretable."))
      (show-plot-help))

  stressp))

(defmeth cmds-model :mds-2d-plot (&optional (stream t))
  (if (not (eq current-object self)) (setcm self))
  (setf *mds* self)
  (setf pp (plot-points (col (send self :xmatrix) 
                             (iseq (send self :number-dimensions)))
               :show nil 
               :scale-type 'fixed
               :title "Stimulus Plane"
               :variable-labels (list "Dimension 1" "Dimension 2" 
                     "Dimension 3" "Dimension 4" "Dimension 5" "Dimension 6" 
                     "Dimension 7" "Dimension 8" "Dimension 9")
               :point-labels (send self :stimulus-names)))
  (send pp :point-symbol (iseq (send pp :num-points)) 'square)
  (send pp :use-color t)
  (send pp :point-color (iseq (send pp :num-points)) 'blue)
  (send pp :showing-labels t)
  (send pp :linked t)
  (send pp :margin 0 17 0 0)
  (send pp :add-overlay (send vista-graph-overlay-proto 
                                       :new :new-x nil :new-y nil :undo t))
 ; (send pp :add-mouse-mode 'relocate-points
 ;       :title "Relocate Point"
 ;       :click :do-nothing
 ;       :cursor 'cross)
  (send pp :add-mouse-mode 'point-moving
      :title "Drag Point"
      :cursor 'finger
      :click :do-point-moving)
 
  (send pp :adjust-to-data)
  (setf minppxy (min (combine (col (send self :xmatrix) 
                                   (iseq (send self :number-dimensions))))))
  (setf maxppxy (max (combine (col (send self :xmatrix) 
                                   (iseq (send self :number-dimensions))))))
  (setf gnrpp (get-nice-range minppxy maxppxy 5))
  (send pp :range 0 (first gnrpp) (second gnrpp) :draw nil)
  (send pp :range 1 (first gnrpp) (second gnrpp) :draw nil)
  (send pp :x-axis t t (third gnrpp) :draw nil)
  (send pp :y-axis t t (third gnrpp) :draw nil)

  (defmeth pp :do-point-moving (x y a b)
    (let* ((pti      (send self :drag-point x y))
           (xvaryvar (send self :content-variables))
           (xvar     (first  xvaryvar))
           (yvar     (second xvaryvar))
           (x nil)
           (y nil))
      (when pti
            (setf x (send self :point-coordinate xvar pti))   
            (setf y (send self :point-coordinate yvar pti))
            (send current-object :use-new-point pti xvar yvar x y))))

  (defmeth pp :undo-graph-change (m1 m2)
    (cond
      (m1 (send *mds* :back-to-start))
      (t  (send *mds* :back-just-one)))
    )

  (defmeth pp :plot-help ()
    (plot-help-window (strcat "Help for " (send self :title)))
    (paste-plot-help (format nil "The STIMULUS PLANE plot is a scatterplot that shows a 2-dimensional view of the MDS stimulus space.~2%"))
    (paste-plot-help (format nil "The plot is like other scatterplots, except it has a special mouse mode which is designed to help you guide the iterative process. In addition, the plot has an UNDO button to undo the changes you make to the iterative process.~2%"))
    (paste-plot-help (format nil "DRAG POINT~%The MOUSE button can be used to obtain a dialog box presenting the selection of mouse modes. The DRAG POINT mouse mode allows you to drag individual points to new locations in the plot. Simply locate your cursor (a pointing finger) on a point, and drag it to a new location. Each time you do this, ViSta will display the point's new postion in the STIMULUS PLANE MATRIX and STIMULUS SPACE windows, and will recalculate and display the new Stress value in the STRESS window.~2%"))
    (paste-plot-help (format nil "UNDO BUTTON~%The UNDO button can be used to undo the changes created by the DRAG POINT mouse mode. If you click on the button, the last point-move is undone. A shift-click undoes all changes and returns the space to its initial state.~2%"))  
    (show-plot-help))
  pp)

(defmeth cmds-model :mds-3d-scatterplot (&optional (stream t))
  (setf sm (scatterplot-matrix (col (send self :xmatrix) (iseq (send self :number-dimensions)))
                               :show nil
                      :title "Stimulus Plane Matrix"
                      :variable-labels (list "Dim1" "Dim2" 
                        "Dim3" "Dim4" "Dim5" "Dim6" "Dim7" "Dim8" "Dim9")                          
                      :point-labels (send self :stimulus-names)
                      ))
  (send sm :linked t)
  (send sm :point-symbol (iseq (send sm :num-points)) 'square)
  (send sm :use-color t)
  (send sm :point-color (iseq (send sm :num-points)) 'blue)
  (send sm :margin 0 17 0 0)
  (send sm :add-overlay (send vista-graph-overlay-proto 
                                       :new :new-x nil :new-y nil))
  (send sm :adjust-to-data)

  (defmeth sm :do-variable-focus (x y m1 m2)
"Method to focus on variable subplots modified to work for mds-model. Assumes that two other plots exist.  These plots MUST be named pp (the scatterplot) and sp (the spin-plot).  A click on a subplot sends it to scatterplot.  Two or three shift-clicks send first three selected variables to spin-plot and first two to scatterplot."
    (let ((cur-var (send self :current-variables))
          )
      (when (not m1)
            (when (/= (select cur-var 0) (select cur-var 1))
                  (send pp :current-variables 
                        (select cur-var 0) (select cur-var 1) )
                  (send pp :range (select cur-var 0) (first gnrpp) (second gnrpp) :draw nil)
                  (send pp :range (select cur-var 1) (first gnrpp) (second gnrpp) :draw nil)
                  (send pp :x-axis t t (third gnrpp) :draw nil)
                  (send pp :y-axis t t (third gnrpp) :draw t)
                  )
            (setf spin-var ())
            )
      (when m1
            (when (= (select cur-var 0) (select cur-var 1))
                  (setf cur-var (list (select cur-var 0))))
            (when (< (length spin-var) 3)
                  (setf spin-var (adjoin (select cur-var 0) spin-var))
                  (when (< (length spin-var) 3)
                        (if (equal (length cur-var) 2)
                            (setf spin-var 
                                  (adjoin (select cur-var 1) spin-var)))))
            (when (= (length spin-var) 3)
                  (send sp :transformation nil :draw nil)
                  (send pp :current-variables 
                        (select spin-var 0) (select spin-var 1) )
                  (send pp :range 0 (first gnrpp) (second gnrpp) :draw nil)
                  (send pp :range 1 (first gnrpp) (second gnrpp) :draw nil)
                  (send pp :x-axis t t (third gnrpp) :draw nil)
                  (send pp :y-axis t t (third gnrpp) :draw nil)
                  (setf spin-var (reverse spin-var))
                  (send sp 
                        :current-variables (select spin-var 0)
                        (select spin-var 1) (select spin-var 2)
                        :draw nil)
                  (send sp :add-box) ;ng
                  ;(send sp :adjust-to-data)
                  (let ((cur-var (send sp :current-variables))
                        )
                    (send sp :set-variables-with-labels cur-var
                          (select (send sp :variable-labels) cur-var))
                    )
                  
                  (setf spin-var ())
                  )
            )
      ))

  (send sm :add-mouse-mode 'focus-on-variables
        :title "Focus On Variables"
        :click :do-variable-focus
        :cursor 'finger)

  (send sm  :mouse-mode 'focus-on-variables)
  sm)

(defmeth cmds-model :mds-3d-spin-plot (&optional (stream t))
  (setf *mds* self)
  (setf sp (spin-plot 
            (col (send self :xmatrix) 
                 (iseq (send self :number-dimensions)))
            :show nil
            :title "Stimulus Space"
            :variable-labels 
            (list "Dim1" "Dim2" "Dim3" "Dim4" "Dim5" "Dim6" "Dim7" "Dim8" "Dim9")
            :point-labels (send self :stimulus-names)
            :scale-type 'fixed))
  (let* ((h (+ (send sp :text-ascent)
               (send sp :text-descent))))
    )
  
  (send sp :scale-type 'centroid-fixed)
  (send sp :add-box) ;ok but ng for switched plots
  (send sp :switch-add-box)
  (send sp :mouse-mode 'hand-rotate)
  (send sp :depth-cuing nil)
  (send sp :point-symbol (iseq (send sp :num-points)) 'square)
  (send sp :use-color t)
  (send sp :point-color (iseq (send sp :num-points)) 'blue)
  (send sp :showing-labels t)
  (send sp :linked t)
  (send sp :add-overlay (send vista-graph-overlay-proto 
             :new :new-x nil :new-y nil :box t :iterate t :undo t))
  (send sp :set-variables-with-labels '(0 1 2)
                   (select (send sp :variable-labels) '(0 1 2)))

  (defmeth sp :iter8 ()
    (let* ((n (array-dimension (send *mds* :xmatrix) 0))
           (m (array-dimension (send *mds* :xmatrix) 1)))
      (send current-model :prev-matrix (matrix (list n m)
              (copy-list (combine (send *mds* :xmatrix))))))
            
    (setf iter-number (get-value-dialog "How many iterations?"
                                        :initial 5))
    (dotimes (i (select iter-number 0))
             (let* ((n (array-dimension (send *mds* :xmatrix) 0))
                    (m (array-dimension (send *mds* :xmatrix) 1))
                    (trys (send stressp :num-points))
                    (old (matrix (list n m) 
                                 (copy-list (combine 
                                             (send *mds* :xmatrix)))))
                    (new (guttman-transform (send *mds* :xmatrix)))
                    (stress2 (calc-stress new 
                                          (send *mds*
                                                :transformed-data))))
               (send stressp :add-points 
                     (list (+ 1 trys)) (list stress2) :color 'red)
               (send stressp :add-lines-with-points :color 'red)
               (send stressp :point-label trys
                     (format nil "~5,4f" 
                             (send stressp :point-coordinate 1 trys)))
               (send stressp :point-state (- trys 1) 'normal)
               (send stressp :point-state trys 'selected)
               (send stressp :redraw)
               (send *mds* :stress stress2)
               (send *mds* :old-matrix old)
               (send *mds* :xmatrix new))
             (send *mds* :new-sm-points)
             (send *mds* :new-sp-points)
             (send *mds* :new-pp-points)
             ;(break)
             ))

  (defmeth sp :plot-help ()
    (plot-help-window (strcat "Help for " (send self :title)))
    (paste-plot-help (format nil "The STIMULUS SPACE window is a SpinPlot showing a 3-dimensional view of the stimulus space. The general details of how to use this plot are given below. There are several specific details for the multidimensional scaling SpinPlot that are mentioned first.~2%"))
(paste-plot-help (format nil "SPECIFIC MDS SPINPLOT HELP~2%"))
(paste-plot-help (format nil "The MDS SpinPlot has two special buttons at the top. These are the ITER and UNDO buttons. They both control the iterative process used to optimally locate the stimulus points.~2%"))
(paste-plot-help (format nil "ITER BUTTON~%When you click on the ITER button you will see a dialog window that lets you enter the maximum number of iterations to be performed. When you specify a number and click OK, the iterations will take place. You will see stimulus points move in the three windows that provide views of the stimulus space (SCATMAT, STIMULUS SPACE and STIMULUS PLANES), and you will see new Stress values added to the STRESS window.~2%"))
(paste-plot-help (format nil "UNDO BUTTON~%The UNDO button undoes iterations. There are three ways this button can be used.~%CLICK: If you simply click on it, the last group of iterations is undone (a group of iterations is the set of iterations that were performed the last time you used the ITER button).~%SHIFT-CLICK: If you shift-click on the button, all iterations are undone and the space is returned to its initial state.~%OPTION-CLICK: If you option-click on the button the last iteration is undone (this provides a way to rock back and forth between the last two iterations).~2%"))
(paste-plot-help (format nil "GENERAL SPINPLOT HELP~2%"))
    (show-plot-help)
    (call-next-method :flush nil)
    )

  (defmeth sp :undo-graph-change (m1 m2)
    (cond
      (m1 (send *mds* :back-to-start))
      (m2 (send *mds* :back-just-one))
      (t  (send *mds* :undo-iterations))))
    
      
  (defmeth sp :set-variables-with-labels (v labs)                                 
    (let ((n (send self :num-variables)))                                   
      (send self :variable-label (iseq n) (repeat "" n))             
      (send self :variable-label v labs)                                           
      (apply #'send self :current-variables v)
      ))
  sp)

(defmeth cmds-model :name-plot (&optional (stream t))
  (setf np (name-list (send self :stimulus-names)
                      :show nil 
                      :title "Stimuli"
                      ))
  (send (send np :menu) :title "Stimuli")
  (send np :fix-name-list)
  ;(send np :has-h-scroll (max (screen-size)))
  ;(send np :has-v-scroll (max (screen-size)))
  (send np :linked t)
  np)

(defmeth cmds-model :initialize ()
  (let* ((current-model-menu-length (length (send *model-menu* :items)))
         )
    (send *desktop* :no-menu-marks *model-menu*)
    (setf model-menu-item-name 
         (concatenate 'string  "MDS-" (send current-data :name)))
    (send *model-menu* :append-items
          (send menu-item-proto :new model-menu-item-name :mark t)
          )
    ))

(defmeth cmds-model :create-data 
  (&key (dialog nil)
        (coefs t)
        (input nil))
  (if (not (eq current-object self)) (setcm self))
  (let ((creator (send *desktop* :selected-icon))
        (desires (list (list (if coefs 0) (if input 1))))
        )
    (if dialog
        (setf desires
              (choose-subset-dialog "Choose Desired Data Objects"
                  '("Stimulus Coefficients (Coordinates)"
                    "Analyzed (Averaged) Input Data")
                    :initial (select desires 0))))
    (when desires
          (when (member '0 (select desires 0))
                (send self :mds-coefs-data-object  creator))
          (when (member '1 (select desires 0))
                (send self :mds-indata-data-object creator)))
    t));fwy 4.28 7/15/97 to make gm work right

(defmeth cmds-model :mds-coefs-data-object (creator)
  (data (concatenate 'string "Coefs-" (send self :name))
   :created creator
   :creator-object self
   :title (concatenate 'string "MDS Coefficients for " 
                       (send self :title))
   :data (combine (select (send self :xmatrix)
                          (iseq (length (send self :stimulus-names)))
                          (iseq (send self :number-dimensions))))
   :variables (mapcar #'(lambda (x) (format nil "Dim~a" x)) 
                      (iseq (send self :number-dimensions)))
   :labels (send self :stimulus-names)
   :types (repeat '"numeric" (send self :number-dimensions)))
  )

(defmeth cmds-model :mds-indata-data-object (creator)
  (data (concatenate 'string "Analyzed-" (send self :name))
   :created creator
   :creator-object self
   :matrices '("Analyzed Data")
   :title (concatenate 'string "Data analyzed by MDS from " 
                       (send self :title))
   :data (combine (send self :data))
   :variables (send self :stimulus-names)
   :labels (send self :stimulus-names))
  )

(defun cmds-model-object (&key dissim-object-name 
                               (matrix-number nil)
                               (matrices-numbers nil)
                               (add-constants nil)
                               (number-dimensions nil)
                               (title "Multidimensional Scaling")
                               (mds-2d-plot t)
                               (mds-3d-scatterplot t)
                               (mds-3d-spin-plot t)
                               (name-plot t)
                               (print-cmds-model t))
  (let ((object (send cmds-model :new dissim-object-name matrix-number
                      matrices-numbers add-constants number-dimensions 
                      mds-2d-plot mds-3d-scatterplot mds-3d-spin-plot
                      name-plot print-cmds-model)))
    (send object :menu (concatenate 'string "MDS-" (send current-data :name)))
    (setf current-model object)
    (setf current-object object)
    (send object :title title)
;next line moved to multidimensional scaling constructor function by fwy 4.27
;   (send *toolbox* :copy-tool-icon 3)
    (send *model-menu* :enabled t)
    (send object :add-model-menu-item "MDS")
;added to fix menu initialization fwy f.27
;fwy4.28 modified to work with guidemaps
    (when (not (send *vista* :guidemap)) (setcm object))
    object))                      

(defun mds-options-dialog ()  
  (let* ((d-label (send text-item-proto :new "Dimensions (minimum=3)"))
         (dimensionality-text
          (send edit-text-item-proto :new "3" :text-length 1))
         (cancel (send modal-button-proto :new "Cancel"))
         (ok (send modal-button-proto :new "OK" 
                   :action #'(lambda ()
                       (eval (read (make-string-input-stream
                                          (send dimensionality-text :text))
                                         nil)))
                   ))
         (mds-options-dialog 
          (send modal-dialog-proto :new
                (list (list dimensionality-text d-label)
                      (list ok cancel))
                :default-button ok))
         )
    (send mds-options-dialog :modal-dialog)
    ))

(defmeth cmds-model :use-new-point (i xvar yvar xscore yscore )
  (let* ((scores (list xscore yscore))
         (cur-vars (list xvar yvar))
         (new-matrix (send self :xmatrix))
         (n (array-dimension (send self :xmatrix) 0))
         (m (array-dimension (send self :xmatrix) 1))
         (copy-old (matrix (list n m) 
                           (copy-list (combine 
                                        (send self :xmatrix))))))
  (send self :old-matrix copy-old)
    (if (eq (send pp :mouse-mode) 'relocate-points)
        (setf k (select i 0))
        (setf k i))
    (send pp :point-coordinate xvar k xscore)
    (send pp :point-coordinate yvar k yscore)
    (send pp :redraw)
    
    (send sp :point-coordinate xvar k xscore)
    (send sp :point-coordinate yvar k yscore)
    (send sp :redraw)
    (send sm :point-coordinate xvar k xscore)
    (send sm :point-coordinate yvar k yscore)
    (send sm :redraw)
  (dotimes (j 2)
             (setf (aref new-matrix
                         k
                         (select cur-vars j))
                   (select scores j)))
    (send self :xmatrix new-matrix)
    (send stressp :add-points (list (+ 1 (send stressp :num-points)))
          (list (calc-stress new-matrix (send self :transformed-data)))
          :draw nil :color 'red)
    (send stressp :add-lines-with-points :color 'red)


    (send stressp :point-label (- (send stressp :num-points) 1)
          (format nil "~5,4f" 
                  (send stressp :point-coordinate 1 
                        (- (send stressp :num-points) 1))))
    (send stressp :add-lines-with-points :color 'red)
    (send stressp :point-state (- (send stressp :num-points) 2) 'normal)
    (send stressp :point-state (- (send stressp :num-points) 1) 'selected)

    (send stressp :redraw)))

(defun multidimensional-scaling 
  (&key 
   (data current-data)
   (title "Multidimensional Scaling")
   (name nil)
   (dialog nil)
   (dimensions 3)
   )
"ViSta function to perform Multidimensional Scaling.  
With no arguments, performs a 3-dimensional scaling using all active data matrices in the current data. Keyword arguments are:
:DIMENSIONS followed by an integer to specify the dimensionality of the analysis (default - and minimum - is 3);
:DATA followed by the name of the data to be analyzed (default: current-data);
:TITLE followed by a character string (default: Multidimensional Scaling);
:DIALOG followed by t (to display parameters dialog box) or nil (default)."
  (let ((object nil)
        )
    (if (not (eq current-object data)) (setcd data))
    (if (not name) (strcat "MDS-" (send current-data :name)))
;next statement moved from cmds-model constructor function fwy 4.27
    (send *toolbox* :copy-tool-icon 3)
    (if dialog (setf dimensions (mds-options-dialog)))
    (cond
      ((not dimensions)
       (send *toolbox* :reset-button 3))
      ((>= dimensions 3)
       (setf object 
             (cmds-model-object 
              :dissim-object-name data
              :matrices-numbers 
              ($position (send current-data :active-matrices '(all))
                         (send current-data :matrices)) 
              :title title
              :add-constants t
              :number-dimensions dimensions)))
      (t
       (send *toolbox* :reset-button 3)
       (error-message "Minimum dimensionality is 3.")))
    object))
