home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD2.bin / bbs / misc / aspringies-1.0.lha / ASpringies / src / obj.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-24  |  15.1 KB  |  664 lines

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