home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / x / volume14 / xpsringies / part03 / obj.c next >
Encoding:
C/C++ Source or Header  |  1991-08-27  |  14.8 KB  |  671 lines

  1. /* obj.c -- xspringies object (masses, springs) handling
  2.  * Copyright (C) 1991  Douglas M. DeCarlo
  3.  *
  4.  * This file is part of XSpringies, a mass and spring simulation system for X
  5.  *
  6.  * XSpringies is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 1, or (at your option)
  9.  * any later version.
  10.  *
  11.  * XSpringies is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  * 
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with XSpringies; see the file COPYING.  If not, write to
  18.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  */
  21.  
  22. #include "defs.h"
  23. #include "obj.h"
  24.  
  25. #define MPROXIMITY    8.0
  26. #define SPROXIMITY    8.0
  27.  
  28. /* Object globals */
  29. mass *masses;
  30. spring *springs;
  31. int num_mass, num_spring;
  32. static int num_mass_alloc, num_spring_alloc;
  33. int fake_mass, fake_spring;
  34. static mass *masses_save = NULL;
  35. static spring *springs_save = NULL;
  36. static int num_mass_saved, num_mass_savedalloc, num_spring_saved, num_spring_savedalloc;
  37.  
  38. /* init_objects: create an initial set of masses and
  39.    springs to work with
  40.    */
  41. void init_objects()
  42. {
  43.     /* Create initial objects */
  44.     num_mass = 0;
  45.     num_mass_alloc = ALLOC_SIZE * 2;
  46.     masses = (mass *)xmalloc(sizeof(mass) * num_mass_alloc);
  47.  
  48.     num_spring = 0;
  49.     num_spring_alloc = ALLOC_SIZE;
  50.     springs = (spring *)xmalloc(sizeof(spring) * num_spring_alloc);
  51.     
  52.     fake_mass = create_mass();
  53.     masses[fake_mass].status = S_FIXED;
  54.     fake_spring = create_spring();
  55.     springs[fake_spring].status = 0;
  56.  
  57.     add_massparent(fake_mass, fake_spring);
  58.     springs[fake_spring].m1 = fake_mass;
  59. }
  60.  
  61. void attach_fake_spring(tomass)
  62. int tomass;
  63. {
  64.     add_massparent(fake_mass, fake_spring);
  65.     springs[fake_spring].m2 = tomass;
  66.     springs[fake_spring].status |= S_ALIVE;
  67.     springs[fake_spring].ks = mst.cur_ks;
  68.     springs[fake_spring].kd = mst.cur_kd;
  69. }
  70.  
  71. void kill_fake_spring()
  72. {
  73.     springs[fake_spring].status &= ~S_ALIVE;
  74. }
  75.  
  76. void move_fake_mass(mx, my)
  77. int mx, my;
  78. {
  79.     masses[fake_mass].x = mx;
  80.     masses[fake_mass].y = my;
  81. }
  82.  
  83. /* create_mass: return the index for a new mass,
  84.    possibly allocating more space if necesary
  85.    */
  86. int create_mass()
  87. {
  88.     if (num_mass >= num_mass_alloc) {
  89.     /* Allocate more masses */
  90.     num_mass_alloc += ALLOC_SIZE;
  91.     masses = (mass *)xrealloc(masses, sizeof(mass) * num_mass_alloc);
  92.     }
  93.     
  94.     /* Set parameters for new mass */
  95.     masses[num_mass].x = masses[num_mass].y = 0.0;
  96.     masses[num_mass].vx = masses[num_mass].vy = 0.0;
  97.     masses[num_mass].ax = masses[num_mass].ay = 0.0;
  98.     masses[num_mass].mass = masses[num_mass].elastic = 0.0;
  99.     masses[num_mass].radius = masses[num_mass].num_pars = 0;
  100.     masses[num_mass].pars = NULL;
  101.     masses[num_mass].status = S_ALIVE;
  102.  
  103.     /* Return next unused mass */
  104.     return num_mass++;
  105. }
  106.  
  107. /* create_spring: return the index for a new spring,
  108.    possibly allocating more space if necesary
  109.    */
  110. int create_spring()
  111. {
  112.     if (num_spring >= num_spring_alloc) {
  113.     /* Allocate more springs */
  114.     num_spring_alloc += ALLOC_SIZE;
  115.     springs = (spring *)xrealloc(springs, sizeof(spring) * num_spring_alloc);
  116.     }
  117.  
  118.     /* Set parameters for new spring */
  119.     springs[num_spring].ks = springs[num_spring].kd = 0.0;
  120.     springs[num_spring].restlen = 0.0;
  121.     springs[num_spring].m1 = springs[num_spring].m2 = 0;
  122.     springs[num_spring].status = S_ALIVE;
  123.  
  124.     /* Return next unused spring */
  125.     return num_spring++;
  126. }
  127.  
  128. void add_massparent(which, parent)
  129. int which, parent;
  130. {
  131.     int len = masses[which].num_pars++;
  132.  
  133.     masses[which].pars = (int *)xrealloc(masses[which].pars, (len + 1) * sizeof(int));
  134.  
  135.     masses[which].pars[len] = parent;
  136. }
  137.  
  138. void del_massparent(which, parent)
  139. int which, parent;
  140. {
  141.     int i;
  142.  
  143.     if (masses[which].status & S_ALIVE) {
  144.     for (i = 0; i < masses[which].num_pars; i++) {
  145.         if (masses[which].pars[i] == parent) {
  146.         if (i == masses[which].num_pars - 1) {
  147.             masses[which].num_pars--;
  148.         } else {
  149.             masses[which].pars[i] = masses[which].pars[--masses[which].num_pars];
  150.         }
  151.         return;
  152.         }
  153.     }
  154.     }
  155. }
  156.  
  157. /* delete_spring: delete a particular spring
  158.  */
  159. void delete_spring(which)
  160. int which;
  161. {
  162.     if (springs[which].status & S_ALIVE) {
  163.         springs[which].status = 0;
  164.     del_massparent(springs[which].m1, which);
  165.     del_massparent(springs[which].m2, which);
  166.     }
  167. }
  168.  
  169. /* delete_mass: delete a particular mass, and all springs
  170.    directly attached to it
  171.    */
  172. void delete_mass(which)
  173. int which;
  174. {
  175.     int i;
  176.  
  177.     if (masses[which].status & S_ALIVE) {
  178.     masses[which].status = 0;
  179.  
  180.     /* Delete all springs connected to it */
  181.     for (i = 0; i < masses[which].num_pars; i++) {
  182.         delete_spring(masses[which].pars[i]);
  183.     }
  184.     }
  185.  
  186.     if (which == mst.center_id)
  187.       mst.center_id = -1;
  188. }
  189.  
  190. /* delete_selected: delete all objects which
  191.    are currently selected
  192.    */
  193. void delete_selected()
  194. {
  195.     int i;
  196.  
  197.     for (i = 0; i < num_mass; i++) {
  198.     if (masses[i].status & S_SELECTED) {
  199.         delete_mass(i);
  200.     }
  201.     }
  202.  
  203.     for (i = 0; i < num_spring; i++) {
  204.     if (springs[i].status & S_SELECTED) {
  205.         delete_spring(i);
  206.     }
  207.     }
  208. }
  209.  
  210. void delete_all()
  211. {
  212.     int i;
  213.  
  214.     for (i = 0; i < num_mass; i++) {
  215.     free(masses[i].pars);
  216.     }
  217.     free(masses);
  218.     num_mass = num_mass_alloc = 0;
  219.     free(springs);
  220.     num_spring = num_spring_alloc = 0;
  221.     mst.center_id = -1;
  222. }
  223.  
  224. void reconnect_masses()
  225. {
  226.     int i;
  227.  
  228.     for (i = 0; i < num_mass; i++) {
  229.     masses[i].num_pars = 0;
  230.     masses[i].pars = NULL;
  231.     }
  232.  
  233.     for (i = 0; i < num_spring; i++) {
  234.     add_massparent(springs[i].m1, i);
  235.     add_massparent(springs[i].m2, i);
  236.     }
  237. }
  238.  
  239. void restore_state()
  240. {
  241.     delete_all();
  242.  
  243.     if (masses_save != NULL) {
  244.     num_mass = num_mass_saved;
  245.     num_mass_alloc = num_mass_savedalloc;
  246.     num_spring = num_spring_saved;
  247.     num_spring_alloc = num_spring_savedalloc;
  248.  
  249.     masses = (mass *)xmalloc(sizeof(mass) * num_mass_alloc);
  250.     bcopy(masses_save, masses, sizeof(mass) * num_mass_alloc);
  251.     springs = (spring *)xmalloc(sizeof(spring) * num_spring_alloc);
  252.     bcopy(springs_save, springs, sizeof(spring) * num_spring_alloc);
  253.  
  254.     reconnect_masses();
  255.     }
  256. }
  257.  
  258. void save_state()
  259. {
  260.     masses_save = (mass *)xmalloc(sizeof(mass) * num_mass_alloc);
  261.     bcopy(masses, masses_save, sizeof(mass) * num_mass_alloc);
  262.     num_mass_saved = num_mass;
  263.     num_mass_savedalloc = num_mass_alloc;
  264.  
  265.     springs_save = (spring *)xmalloc(sizeof(spring) * num_spring_alloc);
  266.     bcopy(springs, springs_save, sizeof(spring) * num_spring_alloc);
  267.     num_spring_saved = num_spring;
  268.     num_spring_savedalloc = num_spring_alloc;
  269. }
  270.  
  271. /* nearest_object:  Find the nearest spring or mass to the position
  272.    (x,y), or return -1 if none are close.  Set is_mass accordingly
  273.    */
  274. int nearest_object(x, y, is_mass)
  275. int x, y;
  276. boolean *is_mass;
  277. {
  278.     int i, closest = -1;
  279.     double dist, min_dist = MPROXIMITY * MPROXIMITY, rating, min_rating = draw_wid * draw_ht;
  280.     boolean masses_only = *is_mass;
  281.  
  282.     *is_mass = TRUE;
  283.  
  284.     if (masses_only)
  285.       min_dist = min_dist * 36;
  286.  
  287.     /* Find closest mass */
  288.     for (i = 0; i < num_mass; i++) {
  289.     if (masses[i].status & S_ALIVE) {
  290.         if ((dist = SQR(masses[i].x - (double)x) + SQR(masses[i].y - (double)y) - (double)SQR(masses[i].radius)) < min_dist) {
  291.         rating = SQR(masses[i].x - (double)x) + SQR(masses[i].y - (double)y);
  292.         if (rating < min_rating) {
  293.             min_dist = dist;
  294.             min_rating = rating;
  295.             closest = i;
  296.         }
  297.         }
  298.     }
  299.     }
  300.  
  301.     if (closest != -1)
  302.       return closest;
  303.  
  304.     if (masses_only)
  305.       return -1;
  306.  
  307.     *is_mass = TRUE;
  308.  
  309.     min_dist = SPROXIMITY;
  310.  
  311.     /* Find closest spring */
  312.     for (i = 0; i < num_spring; i++) {
  313.     double x1, x2, y1, y2;
  314.  
  315.     if (springs[i].status & S_ALIVE) {
  316.         x1 = masses[springs[i].m1].x;
  317.         y1 = masses[springs[i].m1].y;
  318.         x2 = masses[springs[i].m2].x;
  319.         y2 = masses[springs[i].m2].y;
  320.         
  321.         if (x > MIN(x1, x2) - SPROXIMITY && x < MAX(x1, x2) + SPROXIMITY &&
  322.         y > MIN(y1, y2) - SPROXIMITY && y < MAX(y1, y2) + SPROXIMITY) {
  323.         double a1, b1, c1, dAB, d;
  324.         
  325.         a1 = y2 - y1;
  326.         b1 = x1 - x2;
  327.         c1 = y1 * x2 - y2 * x1;
  328.         dAB = sqrt((double)(a1*a1 + b1*b1));
  329.         d = (x * a1 + y * b1 + c1) / dAB;
  330.         
  331.         dist = ABS(d);
  332.         
  333.         if (dist < min_dist) {
  334.             min_dist = dist;
  335.             closest = i;
  336.             *is_mass = FALSE;
  337.         }
  338.         }
  339.     }
  340.     }
  341.  
  342.     return closest;
  343. }
  344.  
  345. void eval_selection()
  346. {
  347.     int i;
  348.     double sel_mass, sel_elas, sel_ks, sel_kd;
  349.     boolean sel_fix;
  350.     boolean found = FALSE, changed = FALSE;
  351.     boolean mass_same, elas_same, ks_same, kd_same, fix_same;
  352.  
  353.     for (i = 0; i < num_mass; i++) {
  354.     if (masses[i].status & S_SELECTED) {
  355.         if (found) {
  356.         if (mass_same && masses[i].mass != sel_mass) {
  357.             mass_same = FALSE;
  358.         }
  359.         if (elas_same && masses[i].elastic != sel_elas) {
  360.             elas_same = FALSE;
  361.         }
  362.         if (fix_same && (masses[i].status & S_FIXED)) {
  363.             fix_same = FALSE;
  364.         }
  365.         } else {
  366.         found = TRUE;
  367.         sel_mass = masses[i].mass;
  368.         mass_same = TRUE;
  369.         sel_elas = masses[i].elastic;
  370.         elas_same = TRUE;
  371.             sel_fix = (masses[i].status & S_FIXED);
  372.         fix_same = TRUE;
  373.         }
  374.     }
  375.     }
  376.  
  377.     if (found) {
  378.     if (mass_same && sel_mass != mst.cur_mass) {
  379.         mst.cur_mass = sel_mass;
  380.         changed = TRUE;
  381.     }
  382.     if (elas_same && sel_elas != mst.cur_rest) {
  383.         mst.cur_rest = sel_elas;
  384.         changed = TRUE;
  385.     }
  386.     if (fix_same && sel_fix != mst.fix_mass) {
  387.         mst.fix_mass = sel_fix;
  388.         changed = TRUE;
  389.     }
  390.     }
  391.     
  392.     found = FALSE;
  393.     for (i = 0; i < num_spring; i++) {
  394.     if (springs[i].status & S_SELECTED) {
  395.         if (found) {
  396.         if (ks_same && springs[i].ks != sel_ks) {
  397.             ks_same = FALSE;
  398.         }
  399.         if (ks_same && springs[i].ks != sel_ks) {
  400.             ks_same = FALSE;
  401.         }
  402.         } else {
  403.         found = TRUE;
  404.         sel_ks = springs[i].ks;
  405.         ks_same = TRUE;
  406.             sel_kd = springs[i].kd;
  407.         kd_same = TRUE;
  408.         }
  409.     }
  410.     }
  411.  
  412.     if (found) {
  413.     if (ks_same && sel_ks != mst.cur_ks) {
  414.         mst.cur_ks = sel_ks;
  415.         changed = TRUE;
  416.     }
  417.     if (kd_same && sel_kd != mst.cur_kd) {
  418.         mst.cur_kd = sel_kd;
  419.         changed = TRUE;
  420.     }
  421.     }
  422.  
  423.     if (changed) {
  424.     redraw_widgets(FALSE);
  425.     }
  426. }
  427.  
  428. boolean anything_selected()
  429. {
  430.     int i;
  431.  
  432.     for (i = 0; i < num_mass; i++) {
  433.     if (masses[i].status & S_SELECTED)
  434.       return TRUE;
  435.     }
  436.     for (i = 0; i < num_spring; i++) {
  437.     if (springs[i].status & S_SELECTED)
  438.       return TRUE;
  439.     }
  440.     return FALSE;
  441. }
  442.  
  443. void select_object(selection, is_mass, shifted)
  444. int selection;
  445. boolean is_mass, shifted;
  446. {
  447.     if (is_mass) {
  448.     if (shifted) {
  449.         masses[selection].status ^= S_SELECTED;
  450.     } else {
  451.         masses[selection].status |= S_SELECTED;
  452.     }
  453.     } else {
  454.     if (shifted) {
  455.         springs[selection].status ^= S_SELECTED;
  456.     } else {
  457.         springs[selection].status |= S_SELECTED;
  458.     }
  459.     }
  460. }
  461.  
  462. void select_objects(ulx, uly, lrx, lry, shifted)
  463. int ulx, uly, lrx, lry;
  464. boolean shifted;
  465. {
  466.     int i;
  467.  
  468.     for (i = 0; i < num_mass; i++) {
  469.     if (masses[i].status & S_ALIVE) {
  470.         if (ulx <= masses[i].x && masses[i].x <= lrx && uly <= masses[i].y && masses[i].y <= lry) {
  471.         select_object(i, TRUE, FALSE);
  472.         }
  473.     }
  474.     }
  475.  
  476.     for (i = 0; i < num_spring; i++) {
  477.     if (springs[i].status & S_ALIVE) {
  478.         int m1, m2;
  479.  
  480.         m1 = springs[i].m1;
  481.         m2 = springs[i].m2;
  482.  
  483.         if (ulx <= masses[m1].x && masses[m1].x <= lrx && uly <= masses[m1].y && masses[m1].y <= lry &&
  484.         ulx <= masses[m2].x && masses[m2].x <= lrx && uly <= masses[m2].y && masses[m2].y <= lry) {
  485.         select_object(i, FALSE, FALSE);
  486.         }
  487.     }
  488.     }        
  489. }
  490.  
  491. void unselect_all()
  492. {
  493.     int i;
  494.  
  495.     for (i = 0; i < num_mass; i++) {
  496.     if (masses[i].status & S_SELECTED) {
  497.         masses[i].status &= ~S_SELECTED;
  498.     }
  499.     }
  500.  
  501.     for (i = 0; i < num_spring; i++) {
  502.     if (springs[i].status & S_SELECTED) {
  503.         springs[i].status &= ~S_SELECTED;
  504.     }
  505.     }    
  506. }
  507.  
  508. void select_all()
  509. {
  510.     int i;
  511.  
  512.     for (i = 0; i < num_mass; i++) {
  513.     if (masses[i].status & S_ALIVE) {
  514.         masses[i].status |= S_SELECTED;
  515.     }
  516.     }
  517.  
  518.     for (i = 0; i < num_spring; i++) {
  519.     if (springs[i].status & S_ALIVE) {
  520.         springs[i].status |= S_SELECTED;
  521.     }
  522.     }    
  523. }
  524.  
  525. void duplicate_selected()
  526. {
  527.     int i, j, *mapfrom, *mapto, num_map, num_map_alloc, spring_start;
  528.     int which;
  529.  
  530.     spring_start = num_spring;
  531.  
  532.     num_map = 0;
  533.     num_map_alloc = ALLOC_SIZE;
  534.     mapfrom = (int *)xmalloc(sizeof(int) * num_map_alloc);
  535.     mapto = (int *)xmalloc(sizeof(int) * num_map_alloc);
  536.  
  537.     for (i = 0; i < num_mass; i++) {
  538.     if (masses[i].status & S_SELECTED) {
  539.         if (num_map >= num_map_alloc) {
  540.         num_map_alloc += ALLOC_SIZE;
  541.         mapfrom = (int *)xrealloc(mapfrom, sizeof(int) * num_map_alloc);
  542.         mapto = (int *)xrealloc(mapto, sizeof(int) * num_map_alloc);
  543.         }
  544.  
  545.         which = create_mass();
  546.         mapto[num_map] = which;
  547.         mapfrom[num_map] = i;
  548.         num_map++;
  549.         masses[which] = masses[i];
  550.         masses[which].status &= ~S_SELECTED;
  551.         masses[which].num_pars = 0;
  552.         masses[which].pars = NULL;
  553.     }
  554.     }
  555.  
  556.     for (i = 0; i < spring_start; i++) {
  557.     if (springs[i].status & S_SELECTED) {
  558.         boolean m1done, m2done;
  559.  
  560.         m1done = m2done = FALSE;
  561.  
  562.         which = create_spring();
  563.         springs[which] = springs[i];
  564.         springs[which].status &= ~S_SELECTED;
  565.  
  566.         for (j = 0; (!m1done || !m2done) && j < num_map; j++) {
  567.         if (!m1done && springs[which].m1 == mapfrom[j]) {
  568.             springs[which].m1 = mapto[j];
  569.             add_massparent(mapto[j], which);
  570.             m1done = TRUE;
  571.         }
  572.         if (!m2done && springs[which].m2 == mapfrom[j]) {
  573.             springs[which].m2 = mapto[j];
  574.             add_massparent(mapto[j], which);
  575.             m2done = TRUE;
  576.         }
  577.         }
  578.         if (!m1done && !m2done) {
  579.         /* delete spring that isn't connected to anyone */
  580.         delete_spring(which);
  581.         }
  582.     }
  583.     }
  584.  
  585.     free(mapfrom);
  586.     free(mapto);
  587. }
  588.  
  589. void translate_selobj(dx, dy)
  590. int dx, dy;
  591. {
  592.     int i;
  593.  
  594.     for (i = 0; i < num_mass; i++) {
  595.     if (masses[i].status & S_SELECTED) {
  596.         masses[i].x += dx;
  597.         masses[i].y += dy;
  598.     }
  599.     }
  600. }
  601.  
  602. void changevel_selobj(vx, vy, relative)
  603. int vx, vy;
  604. boolean relative;
  605. {
  606.     int i;
  607.  
  608.     for (i = 0; i < num_mass; i++) {
  609.     if (masses[i].status & S_SELECTED) {
  610.         if (relative) {
  611.         masses[i].vx += vx;
  612.         masses[i].vy += vy;
  613.         } else {
  614.         masses[i].vx = vx;
  615.         masses[i].vy = vy;
  616.         }
  617.     }
  618.     }
  619. }
  620.  
  621. void tempfixed_obj(store)
  622. boolean store;
  623. {
  624.     int i;
  625.  
  626.     for (i = 0; i < num_mass; i++) {
  627.     if (masses[i].status & S_SELECTED) {
  628.         if (store) {
  629.         masses[i].status &= ~S_TEMPFIXED;
  630.         if (!(masses[i].status & S_FIXED)) {
  631.             masses[i].status |= (S_TEMPFIXED | S_FIXED);
  632.         }
  633.         } else {
  634.         if (masses[i].status & S_TEMPFIXED) {
  635.             masses[i].status &= ~S_FIXED;
  636.         }
  637.         }
  638.     }
  639.     }
  640. }
  641.  
  642. void set_sel_restlen()
  643. {
  644.     int i;
  645.     double dx, dy;
  646.  
  647.     for (i = 0; i < num_spring; i++) {
  648.     if (springs[i].status & S_SELECTED) {
  649.         dx = masses[springs[i].m1].x - masses[springs[i].m2].x;
  650.         dy = masses[springs[i].m1].y - masses[springs[i].m2].y;
  651.         springs[i].restlen = sqrt(dx * dx + dy * dy);
  652.     }
  653.     }
  654. }
  655.  
  656. void set_center()
  657. {
  658.     int i, cent = -1;
  659.  
  660.     for (i = 0; i < num_mass; i++) {
  661.     if (masses[i].status & S_SELECTED) {
  662.         if (cent != -1)
  663.           return;
  664.  
  665.         cent = i;
  666.     }
  667.     }
  668.  
  669.     mst.center_id = cent;
  670. }
  671.