Subversion Repositories DIN Is Noise

Rev

Rev 2097 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
* rect.cc
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/

#include "mondrian.h"
#include "container.h"
#include "console.h"
#include "utils.h"
#include <utility>
using namespace std;

rect::rect () {
  parent = child1 = child2 = 0;
  total_slits = 0;
  for (int i = 0; i < 4; ++i) nslits[i] = 0;
  split = split::NONE;
  make_random_color ();
  ++ref;
}

void rect::erase (ball* b) {::erase (balls, b);}

void rect::calc_intervals () {
  hint.first = extents.bottom;
  hint.second = extents.top;
  vint.first = extents.left;
  vint.second = extents.right;
}

void rect::get_vertical_interval (pair<float, float>& invl, rect* _root) {
  invl.first = 1.0f + (vint.first - _root->extents.left) * _root->extents.width_1;
  invl.second = 1.0f + (vint.second - _root->extents.left) * _root->extents.width_1;
}

void rect::get_horizontal_interval (pair<float, float>& invl, rect* _root) {
  invl.first = 1.0f + (hint.first - _root->extents.bottom) * _root->extents.height_1;
  invl.second = 1.0f + (hint.second - _root->extents.bottom) * _root->extents.height_1;
}

int rect::add_slit (slit* s, int e) {
  int result = 1;
  int& nse = nslits [e]; // number of slits on this edge
  // for all edges
  float lows [rect::nedges] = {extents.left, extents.bottom, extents.left, extents.bottom};
  float highs [rect::nedges] = {extents.right, extents.top, extents.right, extents.top};
  float low = lows[e];
  if (nse) { // slits already on this edge
    list<slit*>& ls = slits [e]; // slits of this edge
    for (slit_iterator i = ls.begin (), j = ls.end (); i != j; ++i) {
      slit* si = *i;
      if (s->mid < si->start) {
        s->start = max (s->start, low);
        s->end = min (s->end, si->start);
        i = ls.insert (i, s); // inserts sorted

        slit_iterator ip (i); --ip; // slit b4 inserted slit
        slit_iterator in (i); ++in; // slit after inserted slit

        // handle animation of previous and next slits
        slit *ips = *ip, *ins = *in;
        if (ip != j && ips->fdr) ips->anim_end = min (ips->anim_end, s->start);
        if (in != j && ins->fdr) ins->anim_start = max (ins->anim_start, s->end);

        // handle edited slit
        if (mondrian0.editing_slit) {
          int hl = 0;
          slit* eds = mondrian0.slit_lip.slitt; // the edited slit
          if ((ip != j) && (*ip == eds)) { // edited slit is b4 inserted slit
            // slits editable high is inserted slits low
            mondrian0.slit_lip.set_high (s->start);
            hl = 1;
          } else if ((in != j) && (*in == eds)) { // slit after inserted slit is edited slit
            // slit's editable low is inserted slits high
            mondrian0.slit_lip.set_low (s->end);
            hl = 1;
          }
          if (hl && mondrian0.slit_lip.slitt->is_too_small()) mondrian0.remove_slit (mondrian0.slit_lip.slitt);
        }
        goto adder;
      }
      low = si->end;
    }

    // append slit
    // if last slit is currently edited slit, adjusts its high
    //
    slit* sl = ls.back ();
    if (sl == mondrian0.slit_lip.slitt) mondrian0.slit_lip.set_high (s->start);

  } /*else cons << console::cyan << "No slits on edge, adding first slit" << eol;*/

  // append slit
  s->start = max (s->start, low);
  s->end = min (s->end, highs[e]);
  slits[e].push_back (s);
  adder:
    s->anim_start = s->start;
    s->anim_end = s->end;
    ++nse;
    ++total_slits;
    /*cons << console::yellow << "Slit size = " << (s->end - s->start) << eol;
    cons << console::yellow << "Slits on edge = " << nse << eol;*/

    if (s->is_too_small()) result = 0; else s->calc_mid ();
  return result;
}

void rect::update_slits (int e, float minn, float maxx) {
  list<slit*>& ls = slits [e];
  for (slit_iterator i = ls.begin (), j = ls.end (); i != j;) {
    slit* si = *i;
    clamp (minn, si->start, maxx);
    clamp (minn, si->end, maxx);
    if (si->is_too_small()) {
      mondrian0.remove_slit (si);
      i = ls.begin ();
      j = ls.end ();
    } else {
      ++i;
      si->calc_mid ();
    }
  }
}