private boolean matchIn(
      Section currSect,
      List<Section> dataSections,
      int dsi,
      List<Section> qSections,
      PatternContext queryCtx,
      Section lastQuerySect) {
    if (qSections.size() > PatternMatchConfig.MAX_REGEX_IT) {
      return false;
    }
    PatternResult matchValue = null;
    int i = 0;
    List<Section> sectsBlock = new ArrayList<>();
    sectsBlock.add(currSect);

    // Translate the query that is always in a regexp-form (even when there are no repetitions) in
    // an array of sections
    // This until there is only one next element
    while (currSect.getNext().size() == 1 && currSect != lastQuerySect) {
      currSect = currSect.getNext().get(0).getDest();
      sectsBlock.add(currSect);
    }

    if (dsi + sectsBlock.size() + qSections.size() > dataSections.size()) {
      return false; // the next group is too long for the remaining data sections
    }

    // translate the new sections in case of repetitions
    if (qSections.size() > 0) {
      /* TODO if slow could be useful to have a cache (the key could be based on the sections id) to avoid those copies */
      Point lastQSectionsSectPt =
          qSections
              .get(qSections.size() - 1)
              .getPoints()
              .get(qSections.get(qSections.size() - 1).getPoints().size() - 1);
      Point firstSectsBlockPt = sectsBlock.get(0).getPoints().get(0);
      if (firstSectsBlockPt.getX() < lastQSectionsSectPt.getX()) {
        double offset = -firstSectsBlockPt.getX() + lastQSectionsSectPt.getX();
        double offseto = -firstSectsBlockPt.getOrigX() + lastQSectionsSectPt.getOrigX();
        for (i = 0; i < sectsBlock.size(); i++) {
          sectsBlock.set(i, sectsBlock.get(i).translateXCopy(offset, offseto));
        }
      }
    }
    List<Section> newQSections = new ArrayList<>(qSections);
    newQSections.addAll(sectsBlock);

    List<Section> dataSectsForQ = dataSections.subList(dsi, dsi + newQSections.size());

    // If we reached the end of the query we can actually use it
    if (currSect == lastQuerySect
        && (currSect.getNext().size() == 0
            || currSect.getNext().get(0).getSize() != 0
            || currSect.getNext().get(0).getSize() == currSect.getNext().get(0).getTimes())) {
      matchValue = this.calculateMatch(dataSectsForQ, newQSections, queryCtx, false);
      if (matchValue != null) {

        // Keep only one (best) match if the same area is selected in different smooth iterations
        int duplicateMatchIdx =
            PatternMatchConfig.REMOVE_EQUAL_MATCHES
                ? this.searchEqualMatch(matchValue, queryCtx.getMatches())
                : -1;
        if (duplicateMatchIdx == -1) {
          matchValue.setId(queryCtx.getMatches().size()); // new id for the new match
          queryCtx.getMatches().add(matchValue);
        } else if (queryCtx.getMatches().get(duplicateMatchIdx).getMatch()
            > matchValue.getMatch()) {
          matchValue.setId(
              queryCtx
                  .getMatches()
                  .get(duplicateMatchIdx)
                  .getId()); // we leave the old id for the match
          queryCtx.getMatches().set(duplicateMatchIdx, matchValue);
        }
      }
    }

    if (!currSect.getNext().isEmpty()) {
      boolean backLink = false;
      for (i = currSect.getNext().size() - 1;
          i >= 0;
          i--) { // iterate repetitions and after the straight link
        SectionNext next = currSect.getNext().get(i);
        if (currSect == lastQuerySect || i > 0) { // it is a back link
          if (next.getSize() != 0) {
            this.matchIn(next.getDest(), dataSections, dsi, newQSections, queryCtx, lastQuerySect);
          } else if (next.getTimes() < next.getSize()) {
            next.setTimes(next.getTimes() + 1);
            backLink = true; // exclude the straight link only if there is a strict repetition
            this.matchIn(next.getDest(), dataSections, dsi, newQSections, queryCtx, lastQuerySect);
          }
        } else if (!backLink) {
          this.matchIn(next.getDest(), dataSections, dsi, newQSections, queryCtx, lastQuerySect);
        }
      }
    }
    return true;
  }
Given a list of tangents it divides the list of tangents in a list of sections. Each section
shares the same tangent signs (a section could be an increasing curve or a decreasing curve,
but not both)

@return Array of sections.
library-udf/src/main/java/org/apache/iotdb/library/match/PatternExecutor.java