void RepCartoonGeneratePASS1()

in layer2/RepCartoon.cpp [2824:3120]


void RepCartoonGeneratePASS1(PyMOLGlobals *G, RepCartoon *I, ObjectMolecule *obj, CoordSet * cs,
                             nuc_acid_data *ndata){
  int st, nd;
  int a, a1, a3, a4 = 0;
  char *lv = I->LastVisib;
  int trace, trace_mode;
  AtomInfoType *ai, *last_ai = NULL;
  int cartoon_side_chain_helper;
  int cylindrical_helices;
  int fancy_helices;
  int fancy_sheets;
  int parity = 1;
  float *v_c, *v_n, *v_o;
  int cur_car;
  nuc_acid_cap leading_O5p(G, ndata, cs, 3);
  nuc_acid_cap trailing_O3p(G, ndata, cs, 2);

  // settings
  fancy_sheets =
    SettingGet_i(G, cs->Setting, obj->Obj.Setting, cSetting_cartoon_fancy_sheets);
  fancy_helices =
    SettingGet_i(G, cs->Setting, obj->Obj.Setting, cSetting_cartoon_fancy_helices);
  cylindrical_helices =
    SettingGet_i(G, cs->Setting, obj->Obj.Setting, cSetting_cartoon_cylindrical_helices);
  cartoon_side_chain_helper =
    SettingGet_b(G, cs->Setting, obj->Obj.Setting, cSetting_cartoon_side_chain_helper);
  int trace_ostate =
    SettingGet_i(G, cs->Setting, obj->Obj.Setting, cSetting_cartoon_trace_atoms);
  trace_mode =
    SettingGet_i(G, cs->Setting, obj->Obj.Setting, cSetting_trace_atoms_mode);
  auto gap_cutoff =
    SettingGet_i(G, cs->Setting, obj->Obj.Setting, cSetting_cartoon_gap_cutoff);

  // iterate over (sorted) atoms
  for(CoordSetAtomIterator iter(cs); iter.next();) {
    ai = iter.getAtomInfo();

    // cartoon rep for this atom?
    if(!(*(lv++) = GET_BIT(ai->visRep, cRepCartoon)))
      continue;

    const char * ai_name = LexStr(G, ai->name);

    // atom indices
    a = iter.getIdx();
    a1 = iter.getAtm();

    // rings
    if(ndata->ring_anchor
        && ai->protons != cAN_H
        && (ndata->ring_finder_eff >= 3 /* all 5-7 atom rings */
          || (ndata->ring_finder_eff <= 2 /*  C4-containing rings */
            && (WordMatchExact(G, "C4", ai_name, 1)))
          || (ndata->ring_finder_eff == 1
            && (WordMatchExact(G, "C4*", ai_name, 1)
              || WordMatchExact(G, "C4'", ai_name, 1))))) {
      VLACheck(ndata->ring_anchor, int, ndata->n_ring);
      ndata->ring_anchor[ndata->n_ring] = a1;
      ndata->n_ring++;
    }

    // handle alternative conformations
    if (ai->alt[0]) {
      if (!ndata->alt) {
        ndata->alt = ai->alt[0];
      } else if (ai->alt[0] != ndata->alt) {
        if (ai->alt[0] > ndata->alt &&
            (!ndata->next_alt || ai->alt[0] < ndata->next_alt))
          ndata->next_alt = ai->alt[0];
        continue;
      }
    }

    // atom level setting
    trace = AtomSettingGetWD(G, ai, cSetting_cartoon_trace_atoms, trace_ostate);

    // CA or cartoon_trace_atoms
    if(trace || (ai->protons == cAN_C
          && WordMatchExact(G, "CA", ai_name, true)
          && !AtomInfoSameResidueP(G, last_ai, ai))) {

      PRINTFD(G, FB_RepCartoon)
        " RepCartoon: found CA in %d%c; a2 %d\n", ai->resv, ai->getInscode(true), ndata->a2 ENDFD;

      // 3' nucleic acid cap
      if(trailing_O3p.cap())
        ndata->a2 = -1;

      bool is_gap = false;

      // auto-detect CA-only models
      if (!ai->bonded)
        trace = true;

      // check for gap
      if(ndata->a2 >= 0) {
        if(!trace) {
          // CA->N->C->CA = 3 bonds
          if(!ObjectMoleculeCheckBondSep(obj, a1, ndata->a2, 3))
            is_gap = true;
        } else {
          if(!AtomInfoSequential(G, obj->AtomInfo + ndata->a2, ai, trace_mode))
            is_gap = true;
        }
      }

      cur_car = ai->cartoon;

      if (is_gap) {
        int delta = ai->resv - last_ai->resv;
        if (delta < 1 || delta > gap_cutoff || !AtomInfoSameChainP(G, ai, last_ai)) {
          ndata->a2 = -1;
        } else {
          (ndata->cc - 1)->setCCOut(cCartoon_dash);
        }
      }

      last_ai = ai;

      // start new segment?
      if(ndata->a2 < 0)
        ndata->nSeg++;

      (*ndata->fp) = ai->flags;    /* store atom flags */

      // side_chain_helper
      if ((ai->visRep & (cRepLineBit | cRepCylBit | cRepSphereBit)) &&
          AtomSettingGetWD(G, ai, cSetting_cartoon_side_chain_helper,
            cartoon_side_chain_helper)) {
          (*ndata->fp) |= cAtomFlag_no_smooth;
      }

      // secondary structure type
      switch (ai->ssType[0]) {
      case 'H':
      case 'h':
        if(cur_car == cCartoon_auto) {
          cur_car = cylindrical_helices ? cCartoon_skip_helix :
            fancy_helices ? cCartoon_dumbbell : cCartoon_oval;
        }
        (*ndata->ss) = 1;          /* helix */
        parity = 0;
        break;
      case 'S':
      case 's':
        if(cur_car == cCartoon_auto) {
          cur_car = fancy_sheets ? cCartoon_arrow : cCartoon_rect;
        }
        (*ndata->ss) = 2;         /* sheet */
        parity = !parity;
        break;
      default:           /* 'L', 'T', 0, etc. */
        if(cur_car == cCartoon_auto) {
          cur_car = cCartoon_loop;
        }
        parity = 0;
        (*ndata->ss) = 0;
        break;
      }

      if(cur_car == cCartoon_putty)
        ndata->putty_flag = true;

      // coordinates
      copy3f(cs->Coord + 3 * a, ndata->vptr);

      *((ndata->cc)++) = cur_car;
      ndata->a2 = a1;
      ndata->vptr += 3;
      ndata->ss++;
      ndata->fp++;
      *(ndata->sptr++) = ndata->nSeg;
      ndata->nAt++;
      *(ndata->iptr++) = a;

      if (trace) {
        if (a1 == 0 || a1 + 1 == cs->NAtIndex ||
            (a3 = cs->atmToIdx(a1 - 1)) == -1 ||
            (a4 = cs->atmToIdx(a1 + 1)) == -1) {
          zero3f(ndata->voptr);
        } else {
          float t0[3], t1[3];
          subtract3f(cs->coordPtr(a), cs->coordPtr(a3), t0);
          subtract3f(cs->coordPtr(a), cs->coordPtr(a4), t1);
          add3f(t0, t1, ndata->voptr);
          normalize3f(ndata->voptr);
        }
        ndata->voptr += 3;
        continue;
      }

      // pointers to C+N+O coordinates
      v_c = NULL;
      v_n = NULL;
      v_o = NULL;

      // get start (st) and end (nd) indices of residue atoms
      AtomInfoBracketResidueFast(G, obj->AtomInfo, obj->NAtom, a1, &st, &nd);

      // find C+N+O coordinates
      for(a3 = st; a3 <= nd; a3++) {
        a4 = cs->atmToIdx(a3);

        if (a4 == -1)
          continue;

        const char * a3name = LexStr(G, obj->AtomInfo[a3].name);

        if(WordMatchExact(G, "C", a3name, true)) {
          v_c = cs->Coord + 3 * a4;
        } else if(WordMatchExact(G, "N", a3name, true)) {
          v_n = cs->Coord + 3 * a4;
        } else if(WordMatchExact(G, "O", a3name, true)) {
          v_o = cs->Coord + 3 * a4;
        }
      }

      // orientation vector
      if(!(v_c && v_n && v_o)) {
        zero3f(ndata->voptr);
      } else {
        float t0[3], t1[3];
        subtract3f(v_n, v_c, t0); /* t0 = N<---C */
        normalize3f(t0);
        subtract3f(v_n, v_o, t1); /* t1 = N<---O */
        normalize3f(t1);
        cross_product3f(t0, t1, ndata->voptr);
        normalize3f(ndata->voptr);
        if(parity) {
          invert3f(ndata->voptr);
        }
      }
      ndata->voptr += 3;

    } else if(
        !AtomInfoSameResidueP(G, last_ai, ai)
        && (ndata->na_mode != 1 ?
          // P atom
          (ai->protons == cAN_P && WordMatchExact(G, "P", ai_name, true)) :
          // C3* C3' atom
          (ai->protons == cAN_C && (WordMatchExact(G, NUCLEIC_NORMAL1, ai_name, 1) ||
                                    WordMatchExact(G, NUCLEIC_NORMAL2, ai_name, 1))))) {

      // check for gap
      if(ndata->a2 >= 0 &&
          // six bonds between phosphates
          !ObjectMoleculeCheckBondSep(obj, a1, ndata->a2, 6)) {
        /*  3' cap */
        trailing_O3p.cap();
        ndata->a2 = -1;
      }

      last_ai = ai;
      trailing_O3p.set(-1, -1, NULL);

      /*  5' cap */
      if(leading_O5p.active()
          && ndata->a2 < 0
          && !AtomInfoSameResidueP(G, ai, leading_O5p.ai)
          && ObjectMoleculeCheckBondSep(obj, a1, leading_O5p.atm, 5)) {
        leading_O5p.cap();
      }

      leading_O5p.set(-1, -1, NULL);

      /* this is the main nucleic acid cartoon section... */
      nuc_acid(G, ndata, a, a1, ai, cs, obj, true);

    } else if(
        // P -> O3* bond
        AtomInfoSameResidueP(G, last_ai, ai)
        && ndata->a2 >= 0
        && last_ai
        && cAN_P == last_ai->protons
        && cAN_O == ai->protons
        && trailing_O3p.enabled
        && (WordMatchExact(G, "O3'", ai_name, 1) ||
            WordMatchExact(G, "O3*", ai_name, 1))
        && ObjectMoleculeCheckBondSep(obj, a1, ndata->a2, 5)) {
      // remember trailing O3*
      trailing_O3p.set(a, a1, ai);

    } else if(
        // O5* atom
        ai->protons == cAN_O
        && leading_O5p.enabled
        && (WordMatchExact(G, "O5'", ai_name, 1) ||
            WordMatchExact(G, "O5*", ai_name, 1))) {
      leading_O5p.set(a, a1, ai);
    }
  }

  /* BEGIN 3' cap */
  if(trailing_O3p.cap()) {
    ndata->a2 = -1;
  }
}