#' @name ggInterval_radarplot
#' @title Radar plot for symbolic data
#' @description Visualize interval-valued and mixed symbolic data with a
#' radar-style display. Interval-valued variables are represented through
#' their lower and upper bounds, while modal multivalued variables can be
#' shown with stacked bars. When \code{type = "quantile"}, the function
#' summarizes all observations of each interval-valued variable through
#' nested empirical quantile bands.
#' @import ggplot2 ggforce
#' @importFrom gridExtra marrangeGrob
#' @importFrom RSDA is.sym.interval
#' @importFrom tidyr separate
#' @param data A ggInterval object. It can also be either RSDA object or
#' classical data frame(not recommended),which will be automatically convert to ggInterval
#' data.
#' @param layerNumber Number of concentric guide layers in the radar display.
#' @param inOneFig Logical. If \code{TRUE}, draw all selected observations in
#' one figure. Otherwise, generate separate figures for the selected
#' observations.
#' @param showLegend Logical. Whether to show the legend.
#' @param showXYLabs Logical. Whether to show the x- and y-axis labels.
#' @param plotPartial Numeric vector giving the row indices to plot. If
#' \code{NULL}, all observations are used. This argument is ignored when
#' \code{type = "quantile"} because the quantile plot summarizes all
#' observations.
#' @param base_lty Line type used in the base figure.
#' @param base_circle Logical. If \code{TRUE}, add inner guide circles.
#' @param alpha Alpha transparency for filled elements.
#' @param addText Logical. Whether to add interval-valued labels to the plot.
#' @param type Radar representation. Use \code{"default"} for polygon
#' intervals, \code{"rect"} for rectangle intervals, or \code{"quantile"}
#' for the quantile-radar display.
#' @param quantileNum Number of quantile layers when
#' \code{type = "quantile"}.
#' @param Drift Drift term controlling where the radar values begin.
#' @param addText_modal Logical. Whether to add labels for modal
#' multivalued variables.
#' @param addText_modal.p Logical. Whether to add modal percentages.
#' @usage ggInterval_radarplot(data=NULL,layerNumber=3,
#' inOneFig=TRUE,showLegend=TRUE,showXYLabs=FALSE,
#' plotPartial=NULL,
#' alpha=0.5,
#' base_circle=TRUE,
#' base_lty=2,
#' addText=TRUE,
#' type="default",
#' quantileNum=4,
#' Drift=0.5,
#' addText_modal=TRUE,
#' addText_modal.p=FALSE)
#' @examples
#' \donttest{
#' # must specify plotPartial to the rows you want to plot
#' Environment.n <- Environment[, 5:17]
#' ggInterval_radarplot(Environment.n,
#'   plotPartial = 2,
#'   showLegend = FALSE,
#'   base_circle = TRUE,
#'   base_lty = 2,
#'   addText = FALSE
#') +
#'   labs(title = "") +
#'   scale_fill_manual(values = c("gray50")) +
#'   scale_color_manual(values = c("red"))
#'
#' ggInterval_radarplot(Environment,
#'   plotPartial = 2,
#'   showLegend = FALSE,
#'   base_circle = FALSE,
#'   base_lty = 1,
#'   addText = TRUE,
#'   type = "rect"
#') +
#'   labs(title = "") +
#'   scale_fill_manual(values = c("gray50")) +
#'   scale_color_manual(values = c("gray50"))
#'
#' ggInterval_radarplot(
#'   facedata,
#'   base_circle = FALSE,
#'   base_lty = 1,
#'   type = "quantile",
#'   quantileNum = 5,
#'   showLegend = TRUE,
#'   Drift = 0
#' ) +
#'   scale_fill_brewer(palette = "Greys") +
#'   labs(title = "", fill = "Quantiles")
#' }
#'
#' @export
ggInterval_radarplot <- function(data = NULL,
                             layerNumber = 3,
                             inOneFig = TRUE,
                             showLegend = TRUE,
                             showXYLabs = FALSE,
                             plotPartial = NULL,
                             alpha = 0.5,
                             base_circle = TRUE,
                             base_lty = 2,
                             addText = TRUE,
                             type = "default",
                             quantileNum = 4,
                             Drift = 0.5,
                             addText_modal = TRUE,
                             addText_modal.p = FALSE) {
  #globalVariables("varLevels", add = F)
  #utils::globalVariables(c("varLevels"), add=FALSE)
  varLevels <- NULL
  extendUnit <- Drift
  if (extendUnit < 0 | extendUnit > 1) {
    stop("Drift must between 0 to 1.")
  }
  
  #extend plot original xyLimits = 1.25, extendUnit=0, colnamesDrift = 0.1
  colnamesDrift <- 0.18
  xyLimits <- extendUnit + 1.25 + colnamesDrift
  textShift <- 0.065
  textSize <- 4
  textCol <- "gray20"
  #
  
  fillBetween = TRUE #not fix complete
  #notes
  if (dim(data)[1] <= 1) {
    stop("ERROR IN data : data must be full data with observations larger than 1.")
  }
  #setting parameter
  nL <- layerNumber
  if (is.null(plotPartial)) {
    #test data to iData
    ggSymData <- testData(data)
    iData <- ggSymData$intervalData
    indNum <- dim(iData)[1]
    plotPartial <- c(1:indNum)
  } else{
    #checking input format
    if (!"symbolic_tbl" %in% class(data)) {
      stop("ERROR : data must be symbolic data,when plotPartial is on.")
    }
    if (!is.numeric(plotPartial)) {
      stop(
        "ERROR IN plotPartial : the input data must be numeric vector as the row index in full data."
      )
    }
    if (!all(plotPartial <= nrow(data)) || !all(plotPartial > 0)) {
      stop(
        "ERROR IN plotPartial : the input data must be numeric vector as the row index in full data."
      )
    }
    iData <- data
    indNum <- length(plotPartial)
  }
  
  if (!(type %in% c("default", "rect", "quantile"))) {
    warning(paste(
      "There is no type called ",
      type,
      ", automatically set default type."
    ))
    type <- "default"
  }
  
  #data preprocessing
  numericData <- unlist(lapply(iData[, 1:dim(data)[2]] , FUN = RSDA::is.sym.interval))
  
  rawiData <- iData
  allnP <- dim(rawiData)[2]
  propData <- iData[, !numericData]
  iData <- iData[, numericData]
  if ("symbolic_tbl" %in% class(iData)) {
    if (dim(iData)[2] == 0) {
      #all data are symbolic modal
      nP <- 0
    } else{
      #normal type , there are some symbolic interval data (len>1)
      nP <- dim(iData)[2]
    }
  } else{
    #only one symbolic interval data
    nP <- 1
    iData <- rawiData[, c(which(numericData), which(!numericData))]
  }
  
  #someday i will fix this bug ,maybe
  # if(nP < 2){
  #   stop("number of numerical (symbolic interval) data must greater than 2")
  # }
  
  
  #setting quantile argument
  if (type == "quantile") {
    #warning("inOneFig will be unused in type=='quantile'.")
    inOneFig <- TRUE
    indNum <- dim(iData)[1]
    if (!quantileNum %in% c(2:10)) {
      stop("the number of quantile must be in the range [2,10].")
    }
    if (nP < 3) {
      stop("numerical variables must greater than 3 in type=='quantile'")
    }
    if (allnP != nP) {
      warning("nominal variables will be ignore in type=='quantile'")
      allnP <- nP
    }
    plotPartial <- NULL
  }
  
  #test ERROR
  if (type != "quantile") {
    if (indNum > 50 & inOneFig == F) {
      stop("Out of time limits")
    } else if (indNum > 10 & inOneFig == T) {
      stop("Suggest set inOneFig to FALSE when the observations are large.")
    } else if (indNum > 5 & inOneFig == T) {
      warning("Suggest set inOneFig to FALSE when the observations are large.")
    }
  }
  
  #setting original plot
  #p<-generateCircle(nL)+coord_fixed(ratio = 1)
  
  if (base_circle) {
    p <- generateCircle(nL + 1, extendUnit) + coord_fixed(ratio = 1)
  } else{
    p <- ggplot() + coord_fixed(ratio = 1)
  }
  
  if (allnP != nP) {
    d <- generatePoint(allnP, nL, extendUnit)
    d <- d[(allnP * nL - allnP + 1):(allnP * nL), ]
    rawiData <- cbind(iData, propData)
    propData <- propData[plotPartial, ]
  } else{
    rawiData <- iData
    d <- generatePoint(nP, nL, extendUnit)
    d <- d[(nP * nL - nP + 1):(nP * nL), ]
  }
  p <- p + geom_point(data = d, aes(x = d$x, y = d$y))
  #get all variables min max data
  if (nP != 0) {
    allData <- iData[, 1:nP]
    
    
    if (!is.null(plotPartial)) {
      iData <- iData[plotPartial, 1:nP]
    }
    dataList <- lapply(
      1:nP,
      FUN = function(x)
        data.frame(allData[[x]])
    )
    iDataList <- lapply(
      1:nP,
      FUN = function(x)
        data.frame(iData[[x]])
    )
    maxList <- lapply(
      1:nP,
      FUN = function(x)
        max(dataList[[x]])
    )
    minList <- lapply(
      1:nP,
      FUN = function(x)
        min(dataList[[x]])
    )
    minminList <- minList
    maxmaxList <- maxList
    
    #quantile #this will over write iDataList
    if (type == "quantile") {
      indNum <- quantileNum + 1
      figQuaNum <- quantileNum + 3
      sepQua <- seq(0, 1, 1 / figQuaNum)
      for (i in 1:nP) {
        datatmp <- c(iDataList[[i]]$min, iDataList[[i]]$max)
        #extend adjust
        datatmp <- round(quantile(datatmp, sepQua), 2)[-(figQuaNum + 1)][-1] + extendUnit
        #end adjust
        tempMin <- datatmp[1:indNum]
        tempMax <- datatmp[2:(figQuaNum - 1)]
        iDataList[[i]] <- data.frame(min = tempMin, max = tempMax)
      }
    }
    
    if (type == "quantile") {
      maxList <- lapply(
        1:nP,
        FUN = function(x)
          max(iDataList[[x]][, "max"])
      )
      minList <- lapply(
        1:nP,
        FUN = function(x)
          min(iDataList[[x]][, "min"])
      )
      minminList <- minList
      maxmaxList <- maxList
    }
    
    #normalize data to 0,1
    #extend adjust
    normData <- lapply(
      1:nP ,
      FUN = function(x) {
        sapply(
          iDataList[[x]],
          FUN = function(elem) {
            ((elem - minList[[x]]) / (maxList[[x]] - minList[[x]])) + extendUnit
          }
        )
      }
    )
    
    
    
    
    #rescale dataframe to input form which data2Vec need
    minDF <- sapply(
      1:nP,
      FUN = function(x)
        matrix(normData[[x]], ncol = 2)[, 1]
    )
    maxDF <- sapply(
      1:nP,
      FUN = function(x)
        matrix(normData[[x]], ncol = 2)[, 2]
    )
    
    minDF <- matrix(minDF, ncol = nP)
    maxDF <- matrix(maxDF, ncol = nP)
    transMatrix <- d[1:nP, c(3, 4)]
    
    
    
    #convert data to match radar axis scale
    if (type == "quantile") {
      setRowNameDf <- iDataList[[1]]
    } else{
      setRowNameDf <- iData
    }
    plotMin <- data2Vec(
      iData = setRowNameDf,
      data = minDF,
      transMat = transMatrix,
      type,
      quantileNum
    )
    plotMax <- data2Vec(
      iData = setRowNameDf,
      data = maxDF,
      transMat = transMatrix,
      type,
      quantileNum
    )
    
    
    #making labels
    temp <- lapply(
      1:nP,
      FUN = function(x)
        paste(iDataList[[x]][, 1], iDataList[[x]][, 2], sep = ":")
    )
    temp <- lapply(
      1:nP,
      FUN = function(x)
        paste0("[", temp[[x]], "]")
    )
    temp <- matrix(unlist(temp), ncol = indNum, byrow = T)
    groupId <- rep(c(1:indNum), each = nP)
    myLabel = paste(groupId, paste(colnames(iData), temp), sep = " : ")
    
    
    #new a labels variable
    plotMin <- data.frame(plotMin, Variables = myLabel)
    plotMax <- data.frame(plotMax, Variables = myLabel)
    
    #make text in plot
    # minList<-unlist(lapply(1:nP,FUN=function(x) iDataList[[x]][,1]))
    # maxList<-unlist(lapply(1:nP,FUN=function(x) iDataList[[x]][,2]))
    #
    newDf <- data.frame(NULL)
    for (i in 1:indNum) {
      for (u in 1:nP) {
        newDf <- rbind(newDf, iDataList[[u]][i, ])
      }
    }
    
    textMin <- as.data.frame(cbind(plotMin, min = newDf$min))
    textMax <- as.data.frame(cbind(plotMax, max = newDf$max))
    textMin$cos <- textMin$cos + textShift
    textMin$sin <- textMin$sin + textShift
    textMax$cos <- textMax$cos + textShift
    textMax$sin <- textMax$sin + textShift
    
    plotMin$group <- as.factor(plotMin$group)
  }#end if np != 0
  
  #calculate nominal variable (point)
  if (allnP != nP) {
    # preparing the nominal data set
    tmpDf <- data.frame(NULL)
    varNum <- 1
    for (var in colnames(propData)) {
      propDf <- data.frame(NULL)
      counter <- 1
      for (ele in 1:indNum) {
        varPro <- unlist(propData[ele, var])
        propDf[counter:(counter + (length(varPro) / 2) - 1), "varName"] <- rep(var, length(varPro) /
                                                                                 2)
        propDf[counter:(counter + (length(varPro) / 2) - 1), "varLevels"] <-
          paste(varPro[1:(length(varPro) / 2)], round(as.numeric(varPro[(length(varPro) /
                                                                           2 + 1):length(varPro)]), 2), sep = ":")
        propDf[counter:(counter + (length(varPro) / 2) - 1), "prop"] <- as.numeric(varPro[(length(varPro) /
                                                                                             2 + 1):length(varPro)])
        propDf[counter:(counter + (length(varPro) / 2) - 1), "groupid"] <- rep(ele, length(varPro) /
                                                                                 2)
        #extendUnit adjust  quantile(seq(0,1,1/3),seq(0,1,1/3))[2:(3+1)]
        #pos<-seq(0,1,1/((length(varPro)+2)/2))
        pos <- as.numeric(quantile(seq(0, 1 + extendUnit, 1 / ((length(varPro) +
                                                                  2) / 2
        )), seq(0, 1, 1 / ((length(varPro) + 2) / 2
        )))[2:(length(varPro) / 2 + 1)])
        #pos <- pos[-length(pos)][-1]
        #end adjust
        propDf[counter:(counter + (length(varPro) / 2) - 1), "x"] <- d[nP +
                                                                         varNum, 3] * pos
        propDf[counter:(counter + (length(varPro) / 2) - 1), "y"] <- d[nP +
                                                                         varNum, 4] * pos
        counter <- counter + length(varPro) / 2
      }
      tmpDf <- rbind(tmpDf, propDf)
      varNum <- varNum + 1
    }
    propDf <- as.data.frame(tmpDf)
    propDf$groupid <- as.factor(propDf$groupid)
    
    
    # preparing the symbolic(rectangle) to represent nominal data
    totalRectDf <- data.frame(NULL)
    obsG <- 1
    #lastRect <- NULL
    heiList <- list(NULL)
    for (i in 1:indNum) {
      heiList[[i]] <- 0
    }
    for (ele in levels(propDf$groupid)) {
      propDf.ele <- dplyr::filter(propDf, propDf$groupid == ele)
      varG <- 1
      tempRectDf <- data.frame(NULL)
      for (i in unique(as.factor(propDf$varName))) {
        rectDf <- data.frame(NULL)
        propDf.temp <- dplyr::filter(propDf.ele, propDf.ele$varName == i)
        varL <- 1
        heiVec <- NULL
        for (u in 1:dim(propDf.temp)[1]) {
          #re range 0~1 to -0.9~0.5 (1 = 撟喲)
          #print(paste0(ele,i,u))
          #print(propDf.temp)
          thisHei <- reRange(-0.99, -0.8, propDf.temp[u, "prop"])
          heiVec <- cbind(heiVec, thisHei)
          rect <- build3DRect(-0.95, -0.95, thisHei, g = paste0(i, u, ele))
          #print(rect)
          distx <- mean(rect$newx - propDf.temp[u, "x"])
          disty <- mean(rect$newy[13:16] - propDf.temp[u, "y"])
          rect$newx <- rect$newx - distx
          rect$newy <- rect$newy - disty
          
          #add in height
          if (obsG >= 2 && inOneFig) {
            rect$newy <- rect$newy + unlist(heiList[[obsG - 1]][varG])[u]
          }
          
          rect[, "varLevels"] <- varL
          rectDf <- rbind(rectDf, rect)
          varL <- varL + 1
        }#inner for
        heiList[[obsG]][varG] <- list(1 + heiVec)
        if (obsG >= 2) {
          heiList[[obsG]][varG] <- list(unlist(heiList[[obsG - 1]][varG]) + unlist(heiList[[obsG]][varG]))
        }
        rectDf[, "varGroup"] <- varG
        tempRectDf <- rbind(tempRectDf, rectDf)
        varG <- varG + 1
      }# sec for
      tempRectDf[, "obsGroup"] <- obsG
      obsG <- obsG + 1
      # if(!is.null(lastRect)){
      #   tempRectDf$newy <- lastRect$newy+tempRectDf$newy
      # }
      totalRectDf <- rbind(totalRectDf, tempRectDf)
      #lastRect<-tempRectDf
      #print(lastRect)
    }# first for
    
    
    #totalRectDf<-as.data.frame(totalRectDf)
    totalRectDf$varLevels <- as.factor(totalRectDf$varLevels)
    totalRectDf$varGroup <- as.factor(totalRectDf$varGroup)
    totalRectDf$obsGroup <- as.factor(totalRectDf$obsGroup)
    if (nP != 0) {
      levels(propDf$groupid) <- levels(plotMin$group)
    }
  }
  
  #generate cut line for type==rect && build nominal rect
  if (type == "rect") {
    if (nP != 0) {
      cutDf <- c(
        getCutDf(plotMin, transMatrix, nP, indNum),
        getCutDf(plotMax, transMatrix, nP, indNum)
      )
    }
  }
  
  #plot
  if (inOneFig) {
    if (type == "default" || type == "quantile") {
      #if(fillBetween){
      myPolyData <- data.frame(NULL)
      if (nP != 0) {
        for (i in levels(as.factor(plotMin$group))) {
          plotMin.temp <- dplyr::filter(plotMin, plotMin$group == i)
          plotMax.temp <- dplyr::filter(plotMax, plotMin$group == i)
          myPathData <- data.frame(
            x1 = plotMin.temp$cos,
            y1 = plotMin.temp$sin,
            x2 = plotMax.temp$cos,
            y2 = plotMax.temp$sin
          )
          if (allnP == nP) {
            plotMin.rev <- plotMin.temp[nrow(plotMin.temp):1, ]
            newTemp <- rbind(plotMax.temp,
                             plotMax.temp[1, ],
                             plotMin.temp[1, ],
                             plotMin.rev)
            myPolyData <- rbind(myPolyData, newTemp)
          } else{
            #add nominal
            tmp2 <- NULL
            j <- 1
            # print(levels(as.factor(propDf$varName)))
            # print(propDf)
            for (u in unique(as.factor(propDf$varName))) {
              # propDf.temp <- dplyr::filter(propDf,propDf$varName==u) %>%
              #   dplyr::filter(groupid==i)
              
              propDf.temp <- dplyr::filter(propDf, propDf$varName == u)
              propDf.temp <- dplyr::filter(propDf.temp, propDf.temp$groupid ==
                                             i)
              tmp <- propDf.temp[propDf.temp$prop == max(propDf.temp$prop), ]
              tmp <- tmp[1, ]
              tmp2 <- rbind(tmp2, plotMin.temp[1, ])
              tmp2[j, c("cos", "sin")] <- c(tmp$x, tmp$y)
              myPathData <- rbind(myPathData,
                                  data.frame(
                                    x1 = tmp$x,
                                    y1 = tmp$y,
                                    x2 = tmp$x,
                                    y2 = tmp$y
                                  ))
              j <- j + 1
            }
            #propDf.temp <- dplyr::filter(propDf,groupid==i)
            #tmp<-propDf[propDf.temp$prop==max(propDf.temp$prop),]
            #tmp<-tmp[1,] #????銝甈⊿?????瘜? ????洵銝??
            #tmp2<-plotMin.temp[1,]
            #tmp2[,c("cos","sin")]<-c(tmp$x,tmp$y)
            #myPathData<-rbind(myPathData,data.frame(x1=tmp$x,y1=tmp$y,x2=tmp$x,y2=tmp$y))
            
            plotMin.rev <- plotMin.temp[nrow(plotMin.temp):1, ]
            tmp2.rev <- tmp2[nrow(tmp2):1, ]
            newTemp <- rbind(plotMax.temp,
                             tmp2,
                             plotMax.temp[1, ],
                             plotMin.temp[1, ],
                             tmp2.rev,
                             plotMin.rev)
            myPolyData <- rbind(myPolyData, newTemp)
          }
          p <- p + geom_path(data = myPathData,
                             aes(x = myPathData$x1, y = myPathData$y1),
                             lty = 0) +
            geom_path(data = myPathData,
                      aes(x = myPathData$x2, y = myPathData$y2),
                      lty = 0)
        }
      }
      
      if (allnP != nP) {
        if (nP != 0) {
          tmpN <- dim(myPolyData)[1] / indNum
          myPolyData[, "obsGroup"] <- as.factor(rep(1:indNum, each = tmpN))
          tempPolyDf <- myPolyData[, c(1, 2, 3, 5)]
        }
        
        tempRectDf <- totalRectDf[, c(1, 2, 3, 6)]
        
        colnames(tempRectDf) <- c("cos", "sin", "group", "obsGroup")
        #colnames(tempRectDf)<-colnames(tempPolyDf)
        if (nP != 0) {
          polyDf <- as.data.frame(rbind(tempPolyDf, tempRectDf))
        } else{
          polyDf <- tempRectDf
        }
        
        p <- p + geom_polygon(
          data = polyDf,
          aes(
            x = polyDf$cos,
            y = polyDf$sin,
            group = polyDf$group,
            fill = polyDf$obsGroup,
            col = polyDf$obsGroup
          ),
          alpha = alpha
        )
        if (nP != 0) {
          p <- p +  geom_point(data = plotMin, aes(x = plotMin$cos, y = plotMin$sin)) +
            geom_point(data = plotMax, aes(x = plotMax$cos, y = plotMax$sin))
        }
        
      } else{
        if (type == "quantile") {
          p <- p + geom_polygon(
            data = myPolyData,
            aes(
              x = myPolyData$cos,
              y = myPolyData$sin,
              fill = myPolyData$group,
              col = myPolyData$group
            ),
            alpha = alpha
          )
        } else{
          p <- p + geom_polygon(
            data = myPolyData,
            aes(
              x = myPolyData$cos,
              y = myPolyData$sin,
              fill = myPolyData$group,
              col = myPolyData$group
            ),
            alpha = alpha,
            lty = 0
          )
        }
        
        if (type != "quantile") {
          p <- p + geom_point(data = plotMin, aes(x = plotMin$cos, y = plotMin$sin)) +
            geom_point(data = plotMax, aes(x = plotMax$cos, y = plotMax$sin))
        }
        
      }
      
    }
    #else{ #this is else for if(fillbetween)
    else if (type == "rect") {
      #add cut segment
      if (nP != 0) {
        rectPolyData <- data.frame(NULL)
        gId <- 1
        for (g in levels(as.factor(cutDf[[1]]$obsGroup))) {
          cutDf.temp <- lapply(
            1:4,
            FUN = function(x) {
              as.data.frame(dplyr::filter(cutDf[[x]], cutDf[[x]]$obsGroup == g))
            }
          )
          #print(cutDf.temp)
          for (i in 1:nP) {
            tmpDf <- data.frame(
              x = c(
                cutDf.temp[[1]]$x2[i],
                cutDf.temp[[2]]$x2[i],
                cutDf.temp[[4]]$x2[i],
                cutDf.temp[[3]]$x2[i]
              ),
              y = c(
                cutDf.temp[[1]]$y2[i],
                cutDf.temp[[2]]$y2[i],
                cutDf.temp[[4]]$y2[i],
                cutDf.temp[[3]]$y2[i]
              ),
              varGroup = as.factor(rep(gId, 4)),
              obsGroup = as.factor(g)
            )
            rectPolyData <- rbind(rectPolyData, tmpDf)
            gId <- gId + 1
          }
        }
      }
      #print(cutDf)
      #print(rectPolyData)
      #numeric
      if (allnP != nP) {
        tempRectDf <- totalRectDf[, c(1, 2, 3, 6)]
        #colnames(tempRectDf) <- colnames(rectPolyData)
        colnames(tempRectDf) <- c("x", "y", "varGroup", "obsGroup")
        if (nP != 0) {
          levels(tempRectDf$obsGroup) <- levels(rectPolyData$obsGroup)
          rectPolyData <- as.data.frame(rbind(tempRectDf, rectPolyData))
        } else{
          rectPolyData <- tempRectDf
        }
        
      }
      p <- p + geom_polygon(
        data = rectPolyData,
        aes(
          x = .data$x,
          y = .data$y,
          group = .data$varGroup,
          fill = .data$obsGroup,
          col = .data$obsGroup
        ),
        alpha = alpha
      )
      
      
    }
    #nominal
    if (allnP != nP) {
      newPropDf <- as.data.frame(tidyr::separate(
        propDf,
        varLevels,
        into = c("varLevels", "gar"),
        sep = ":",
        convert = F
      ))
      newPropDf <- as.data.frame(dplyr::filter(
        newPropDf,
        newPropDf$groupid == levels(newPropDf$groupid)[1]
      ))
      
      if (addText_modal) {
        p <- p + geom_text(
          data = newPropDf,
          aes(
            x = newPropDf$x + textShift,
            y = newPropDf$y + textShift,
            label = newPropDf$varLevels
          ),
          vjust = 2.15,
          hjust = 0.5,
          size = textSize,
          col = textCol
        )
      }
      #print(totalRectDf)
      
      if (addText_modal.p) {
        tempd <- data.frame(NULL)
        for (i in unique(totalRectDf$varGroup)) {
          temp.varG <- dplyr::filter(totalRectDf, totalRectDf$varGroup == i)
          for (u in levels(temp.varG$obsGroup)) {
            temp.obsG <- dplyr::filter(temp.varG, temp.varG$obsGroup == u)
            for (k in unique(temp.obsG$varLevels)) {
              temp.varL <- dplyr::filter(temp.obsG, temp.obsG$varLevels == k)
              tempd <- rbind(tempd, data.frame(
                x = mean(temp.varL$newx),
                y = mean(temp.varL$newy)
              ))
            }
          }
        }
        propTextDf <- data.frame(tempd, prop = propDf$prop)
        #print(propTextDf)
        p <- p + geom_text(
          data = propTextDf,
          aes(
            x = propTextDf$x + textShift,
            y = propTextDf$y,
            label = round(propTextDf$prop, 2)
          ),
          size = textSize,
          col = textCol
        )
      }
    }
    #print("5")
    # if(allnP!=nP){
    #   p<-p+geom_polygon(data=totalRectDf,aes(x=newx,y=newy,group=group,fill=obsGroup),
    #                     col="black",
    #                     alpha=alpha)+
    #     geom_text(data=propDf,aes(x=propDf$x+textShift,y=propDf$y+textShift,label=varLevels),
    #               vjust=2.75)
    # }
    
    #colnames shift out of figure 0.1 unit (colnamesDrift)
    newD <- shift(d, unit = colnamesDrift)
    p <- p + geom_segment(
      data = d,
      aes(
        x = 0,
        y = 0,
        xend = d$x,
        yend = d$y
      ),
      lty = base_lty,
      alpha = 0.6,
      col = "gray50"
    )
    if (nP != 0) {
      p <- p + geom_point(data = plotMax, aes(
        x = 0,
        y = 0,
        alpha = plotMax$Variables
      )) +
        geom_text(data = newD, aes(
          x = newD$x,
          y = newD$y,
          label = c(colnames(rawiData))
        ))
      
    }
    
    
    
    if (addText && type != "quantile" && nP != 0) {
      p <- p + geom_text(
        data = textMin,
        aes(
          x = textMin$cos,
          y = textMin$sin,
          label = textMin$min
        ),
        size = textSize,
        col = textCol
      ) +
        geom_text(
          data = textMax,
          aes(
            x = textMax$cos,
            y = textMax$sin,
            label = textMax$max
          ),
          size = textSize,
          col = textCol
        )
    }
    if (!showXYLabs) {
      p <- p + scale_x_continuous(labels = NULL,
                                  limits = c(-xyLimits, xyLimits)) +
        scale_y_continuous(labels = NULL,
                           limits = c(-xyLimits, xyLimits)) + xlab(NULL) + ylab(NULL)
    } else{
      #adds scale y continuous label
      yLabelPos <- seq(-xyLimits, xyLimits, (xyLimits - (-xyLimits)) / (nP +
                                                                          1))
      yLabelPos <- yLabelPos[-1]
      yLabelTitle <- paste0(colnames(iData), ": [")
      yLabels <- paste0(yLabelTitle, paste(unlist(minminList), unlist(maxmaxList), sep =
                                             ","), "]")
      yLabels <- c(yLabels, expression(bold(
        "The range of each variable show as follows :"
      )))
      p <- p + scale_x_continuous(limits = c(-xyLimits, xyLimits)) +
        scale_y_continuous(
          breaks = yLabelPos,
          labels = yLabels,
          limits = c(-xyLimits, xyLimits)
        ) + xlab(NULL) + ylab(NULL) +
        scale_x_continuous(labels = NULL,
                           limits = c(-xyLimits, xyLimits))
    }
    #showLegend
    if (showLegend) {
      p <- p + guides(col = "none")
    } else{
      p <- p + guides(fill = "none",
                      col = "none",
                      alpha = "none")
    }
    if (type == "quantile") {
      myTitle <- "Radar : quantile plot"
    } else{
      #myTitle<-paste0("Radar : ",paste(sapply(rownames(iData), paste, collapse=":"), collapse=","))
      myTitle = "Radar plot"
    }
    p <- p + labs(title = myTitle) +
      scale_colour_discrete(name = "Group") +
      scale_alpha_discrete(name = "Interval value of each observation") +
      scale_fill_discrete(name = "Group") +
      theme_bw()
    
    #make circle interpret
    if (base_circle) {
      a <- cos(120 * pi / 180)
      b <- sin(120 * pi / 180)
      #extend adjust quantile(seq(0,myRange,1/nLayer),seq(0,1,1/nLayer))[2:(nLayer+1)]
      tmp <- quantile(seq(0 + extendUnit, 1 + extendUnit, 1 / layerNumber),
                      seq(0, 1, 1 / layerNumber))
      #tmp<-seq(0,1,1/layerNumber)[-1]
      #end adjust
      tmp <- data.frame(
        x = a * tmp,
        y = b * tmp,
        label = paste0(as.character(round((tmp - extendUnit) * 100
        )), "%")
      )
      p <- p + geom_text(data = tmp, aes(
        x = tmp$x,
        y = tmp$y,
        label = tmp$label
      ))
    }
  } else{
    plotList <- NULL
    u <- 1
    for (i in levels(as.factor(plotMin$group))) {
      #print(i)
      if (nP == 0) {
        stop(
          "Cannot allows discrete variables only, under the parameter inOneFig = FALSE,
             please adjust inOneFig to TRUE."
        )
      }
      plotMin.temp <- dplyr::filter(plotMin, plotMin$group == i)
      plotMax.temp <- dplyr::filter(plotMax, plotMax$group == i)
      textMin.temp <- dplyr::filter(textMin, textMin$group == i)
      textMax.temp <- dplyr::filter(textMax, textMax$group == i)
      if (allnP != nP) {
        propDf.temp <- dplyr::filter(propDf, propDf$groupid == levels(propDf$groupid)[u])
        totalRectDf.temp <- dplyr::filter(totalRectDf,
                                          totalRectDf$obsGroup == levels(totalRectDf$obsGroup)[u])
      } else{
        propDf.temp <- 0
        totalRectDf.temp <- 0
      }
      
      if (type == "rect") {
        cutDf.temp <- list(NULL)
        for (k in 1:4) {
          cutDf[[k]]$obsGroup <- as.factor(cutDf[[k]]$obsGroup)
          cutDf.temp[[k]] <- dplyr::filter(cutDf[[k]], cutDf[[k]]$obsGroup ==
                                             levels(cutDf[[k]]$obsGroup)[u])
        }
      } else{
        cutDf.temp <- 0
      }
      
      
      
      #print(paste(u,plotMin.temp))
      base <- plotFun(
        p,
        iData,
        plotMin.temp,
        plotMax.temp,
        d,
        showXYLabs,
        showLegend,
        fillBetween,
        base_circle,
        layerNumber,
        textMin.temp,
        textMax.temp,
        rawiData,
        propDf,
        propDf.temp,
        allnP,
        nP,
        type,
        cutDf.temp,
        totalRectDf.temp,
        addText,
        textShift,
        base_lty,
        alpha,
        xyLimits,
        extendUnit,
        addText_modal,
        addText_modal.p
      )
      
      
      base <- base + labs(title = paste0("Radar : ", rownames(iData)[u])) +
        labs(title = paste0("Radar : ", rownames(iData)[u])) + scale_colour_discrete(name = "Group") +
        scale_alpha_discrete(name = "Interval")
      plotList[[u]] <- base
      u <- u + 1
    }
    
    #print(plotList[[1]])
    #p<-gridExtra::marrangeGrob(plotList,ncol=2,nrow=1)
    myRow <- round(sqrt(indNum))
    myCol <- ceiling(indNum / myRow)
    p <- gridExtra::marrangeGrob(plotList, ncol = myCol, nrow = myRow)
    
  }
  
  if (type == "quantile") {
    colShift <- 4
    myValues <- rev(grey.colors(quantileNum + 1 + colShift))[-c(1:colShift)]
    p <- p + guides(alpha = "none") +
      scale_fill_manual(name = "quantile percentage", values = myValues) +
      scale_colour_manual(values = myValues)
  }
  return(p)
}




plotFun <- function(p,
                    iData,
                    plotMin.temp,
                    plotMax.temp,
                    d,
                    showXYLabs,
                    showLegend,
                    fillBetween,
                    base_circle,
                    layerNumber,
                    textMin.temp,
                    textMax.temp,
                    rawiData,
                    propDf,
                    propDf.temp,
                    allnP,
                    nP,
                    type,
                    cutDf,
                    totalRectDf.temp,
                    addText,
                    textShift,
                    base_lty,
                    alpha,
                    xyLimits,
                    extendUnit,
                    addText_modal,
                    addText_modal.p) {
  #if(fillBetween){
  varLevels <- NULL
  if (type == "default") {
    myPolyData <- data.frame(NULL)
    myPathData <- data.frame(
      x1 = plotMin.temp$cos,
      y1 = plotMin.temp$sin,
      x2 = plotMax.temp$cos,
      y2 = plotMax.temp$sin
    )
    
    if (allnP == nP) {
      plotMin.rev <- plotMin.temp[nrow(plotMin.temp):1, ]
      myPolyData <- rbind(plotMax.temp,
                          plotMax.temp[1, ],
                          plotMin.temp[1, ],
                          plotMin.rev)

    } else{
      #add nominal
      tmp2 <- NULL
      j <- 1
      # print(levels(as.factor(propDf$varName)))
      # print(propDf)
      for (u in unique(as.factor(propDf.temp$varName))) {
        propDf.temp2 <- dplyr::filter(propDf.temp, propDf.temp$varName == u)
        tmp <- propDf.temp2[propDf.temp2$prop == max(propDf.temp2$prop), ]
        tmp <- tmp[1, ]
        tmp2 <- rbind(tmp2, plotMin.temp[1, ])
        tmp2[j, c("cos", "sin")] <- c(tmp$x, tmp$y)
        myPathData <- rbind(myPathData,
                            data.frame(
                              x1 = tmp$x,
                              y1 = tmp$y,
                              x2 = tmp$x,
                              y2 = tmp$y
                            ))
        j <- j + 1
      }
      plotMin.rev <- plotMin.temp[nrow(plotMin.temp):1, ]
      tmp2.rev <- tmp2[nrow(tmp2):1, ]
      newTemp <- rbind(plotMax.temp,
                       tmp2,
                       plotMax.temp[1, ],
                       plotMin.temp[1, ],
                       tmp2.rev,
                       plotMin.rev)
      myPolyData <- rbind(myPolyData, newTemp)
    }
    base <- p + geom_path(data = myPathData, aes(x = myPathData$x1, y =
                                                   myPathData$y1)) +
      geom_path(data = myPathData, aes(x = myPathData$x2, y = myPathData$y2))
    
    
    
    if (allnP != nP) {
      #tmpN<-dim(myPolyData)[1]
      
      this.obs <- totalRectDf.temp$obsGroup[1]
      myPolyData[, "obsGroup"] <- as.factor(this.obs)
      tempRectDf <- totalRectDf.temp[, c(1, 2, 3, 6)]
      
      tempPolyDf <- myPolyData[, c(1, 2, 3, 5)]
      colnames(tempRectDf) <- colnames(tempPolyDf)
      polyDf <- as.data.frame(rbind(tempPolyDf, tempRectDf))
      
      base <- base +
        geom_point(data = plotMin.temp, aes(x = plotMin.temp$cos, y = plotMin.temp$sin)) +
        geom_point(data = plotMax.temp, aes(x = plotMax.temp$cos, y = plotMax.temp$sin))
      
      
      
      
      base <- base + geom_polygon(
        data = polyDf,
        aes(
          x = polyDf$cos,
          y = polyDf$sin,
          group = polyDf$group,
          fill = polyDf$obsGroup,
          col = polyDf$obsGroup
        ),
        alpha = alpha
      )
      
      
      
    } else{
      base <- base + geom_polygon(
        data = myPolyData,
        aes(
          x = myPolyData$cos,
          y = myPolyData$sin,
          fill = myPolyData$group,
          col = myPolyData$group
        ),
        alpha = alpha
      ) +
        geom_point(data = plotMin.temp, aes(x = plotMin.temp$cos, y = plotMin.temp$sin)) +
        geom_point(data = plotMax.temp, aes(x = plotMax.temp$cos, y = plotMax.temp$sin))
    }
    
    # base<-base+geom_polygon(data=myPolyData,aes(x=myPolyData$cos,y=myPolyData$sin,fill=group),alpha = alpha,col="black")
  } else if (type == "rect") {
    #add cut segment
    rectPolyData <- data.frame(NULL)
    gId <- 1
    for (g in levels(as.factor(cutDf[[1]]$obsGroup))) {
      cutDf.temp <- lapply(
        1:4,
        FUN = function(x) {
          as.data.frame(dplyr::filter(cutDf[[x]], cutDf[[x]]$obsGroup == g))
        }
      )
      #print(cutDf.temp)
      for (i in 1:nP) {
        tmpDf <- data.frame(
          x = c(
            cutDf.temp[[1]]$x2[i],
            cutDf.temp[[2]]$x2[i],
            cutDf.temp[[4]]$x2[i],
            cutDf.temp[[3]]$x2[i]
          ),
          y = c(
            cutDf.temp[[1]]$y2[i],
            cutDf.temp[[2]]$y2[i],
            cutDf.temp[[4]]$y2[i],
            cutDf.temp[[3]]$y2[i]
          ),
          varGroup = as.factor(rep(gId, 4)),
          obsGroup = as.factor(g)
        )
        rectPolyData <- rbind(rectPolyData, tmpDf)
        gId <- gId + 1
      }
      
    }
    #print(cutDf)
    #print(rectPolyData)
    #numeric
    if (allnP != nP) {
      tempRectDf <- totalRectDf.temp[, c(1, 2, 3, 6)]
      colnames(tempRectDf) <- colnames(rectPolyData)
      levels(tempRectDf$obsGroup) <- levels(rectPolyData$obsGroup)
      rectPolyData <- as.data.frame(rbind(tempRectDf, rectPolyData))
    }
    base <- p + geom_polygon(
      data = rectPolyData,
      aes(
        x = .data$x,
        y = .data$y,
        group = .data$varGroup,
        fill = .data$obsGroup,
        col = .data$obsGroup
      ),
      alpha = alpha
    )
    
  }#end rect
  
  #add nominal text
  if (allnP != nP) {
    newPropDf <- as.data.frame(tidyr::separate(
      propDf,
      varLevels,
      into = c("varLevels", "gar"),
      sep = ":",
      convert = F
    ))
    newPropDf <- as.data.frame(dplyr::filter(
      newPropDf,
      newPropDf$groupid == levels(newPropDf$groupid)[1]
    ))
    if (addText_modal) {
      base <- base + geom_text(
        data = newPropDf,
        aes(
          x = newPropDf$x + textShift,
          y = newPropDf$y + textShift,
          label = newPropDf$varLevels
        ),
        vjust = 2.75
      )
    }
    
    #print(totalRectDf.temp)
    if (addText_modal.p) {
      tempd <- data.frame(NULL)
      for (i in levels(totalRectDf.temp$varGroup)) {
        temp.varG <- dplyr::filter(totalRectDf.temp, totalRectDf.temp$varGroup ==
                                     i)
        for (k in unique(temp.varG$varLevels)) {
          temp.varL <- dplyr::filter(temp.varG, temp.varG$varLevels == k)
          tempd <- rbind(tempd, data.frame(
            x = mean(temp.varL$newx),
            y = mean(temp.varL$newy)
          ))
        }
      }
      propTextDf <- data.frame(tempd, prop = propDf.temp$prop)
      #print(propTextDf)
      base <- base + geom_text(data = propTextDf,
                               aes(
                                 x = propTextDf$x + textShift,
                                 y = propTextDf$y,
                                 label = round(propTextDf$prop, 2)
                               ))
    }
  }
  
  newD <- shift(d, 0.1)
  base <- base + geom_segment(
    data = d,
    aes(
      x = 0,
      y = 0,
      xend = d$x,
      yend = d$y
    ),
    lty = base_lty,
    alpha = 0.6,
    col = "gray50"
  ) +
    geom_point(data = plotMax.temp, aes(
      x = 0,
      y = 0,
      alpha = plotMax.temp$Variables
    )) +
    geom_text(data = newD, aes(
      x = newD$x,
      y = newD$y,
      label = c(colnames(rawiData))
    ))
  
  if (addText) {
    base <- base + geom_text(data = textMin.temp,
                             aes(
                               x = textMin.temp$cos,
                               y = textMin.temp$sin,
                               label = textMin.temp$min
                             )) +
      geom_text(data = textMax.temp,
                aes(
                  x = textMax.temp$cos,
                  y = textMax.temp$sin,
                  label = textMax.temp$max
                ))
  }
  
  if (!showXYLabs) {
    base <- base + scale_x_continuous(labels = NULL,
                                      limits = c(-xyLimits, xyLimits)) +
      scale_y_continuous(labels = NULL,
                         limits = c(-xyLimits, xyLimits)) + xlab(NULL) + ylab(NULL)
  } else{
    base <- base + scale_x_continuous(limits = c(-xyLimits, xyLimits)) +
      scale_y_continuous(limits = c(-xyLimits, xyLimits))
  }#showLegend
  if (showLegend) {
    base <- base + guides(fill = "none", col = "none")
  } else{
    base <- base + guides(fill = "none",
                          col = "none",
                          alpha = "none")
  }
  
  if (base_circle) {
    a <- cos(120 * pi / 180)
    b <- sin(120 * pi / 180)
    
    #extend adjust quantile(seq(0,myRange,1/nLayer),seq(0,1,1/nLayer))[2:(nLayer+1)]
    tmp <- quantile(seq(0 + extendUnit, 1 + extendUnit, 1 / layerNumber),
                    seq(0, 1, 1 / layerNumber))
    #tmp<-seq(0,1,1/layerNumber)[-1]
    #end adjust
    tmp <- data.frame(
      x = a * tmp,
      y = b * tmp,
      label = paste0(as.character(round((tmp - extendUnit) * 100
      )), "%")
    )
    base <- base + geom_text(data = tmp, aes(
      x = tmp$x,
      y = tmp$y,
      label = tmp$label
    ))
  }
  base <- base + theme_bw() + guides(alpha = "none")
  return(base)
}
data2Vec <- function(iData = NULL,
                     data = NULL,
                     transMat = NULL,
                     type = NULL,
                     quantileNum = NULL) {
  if (dim(data)[2] != dim(transMat)[1]) {
    stop("ERROR : Cannot match data and transMat")
  }
  result = data.frame(NULL)
  if (type == "quantile") {
    for (i in 1:dim(data)[1]) {
      result <- rbind(result, data.frame(data[i, ] * transMat, group = paste(
        paste("Group", as.factor(letters[i])), rownames(iData)[i], sep = " : "
      )))
    }
  } else{
    for (i in 1:dim(data)[1]) {
      result <- rbind(result, data.frame(data[i, ] * transMat, group = paste(
        paste("Group", as.factor(i)), rownames(iData)[i], sep = " : "
      )))
    }
  }
  return(result)
}
generateCircle <- function(nLayer = NULL,
                           extendUnit = 0.5) {
  if (is.null(nLayer) || nLayer <= 0 || nLayer > 30) {
    stop("Illegal layerNumber input. Recommended value will between 2 and 10.")
  }
  circles <- data.frame(
    x0 = rep(0, nLayer),
    y0 = rep(0, nLayer),
    #r = round(seq(0,myRange,1/nLayer)[2:(nLayer+1)],2)
    #r = quantile(seq(0,myRange,1/nLayer),seq(0,1,1/nLayer))[2:(nLayer+1)]
    r = quantile(seq(
      0 + extendUnit, 1 + extendUnit, 1 / (nLayer - 1)
    ), seq(0, 1, 1 / (nLayer - 1)))
  )
  p <- ggplot() +
    ggforce::geom_circle(
      aes(
        x0 = circles$x0,
        y0 = circles$y0,
        r = circles$r
      ),
      data = circles,
      col = "gray50"
    )
  return(p)
}
generatePoint <- function(nPoly = NULL,
                          nLayer = NULL,
                          extendUnit = 0.5) {
  if (is.null(nPoly) || nPoly <= 0 || nPoly > 360) {
    stop("ERROR : Illegal parameter input in nPoly")
  }
  if (is.null(nLayer) || nLayer <= 0 || nLayer > 30) {
    stop("ERROR : Illegal parameter input in nLayer")
  }
  #rList = round(seq(0,1,1/nLayer)[2:(nLayer+1)],2)
  #rList = quantile(seq(0,myRange,1/nLayer),seq(0,1,1/nLayer))[2:(nLayer+1)]
  rList = quantile(seq(0 + extendUnit, 1 + extendUnit, 1 / (nLayer - 1)), seq(0, 1, 1 /
                                                                                (nLayer - 1)))
  degreeUnit <- round(360 / nPoly)
  allPoint <- data.frame(NULL)
  for (r in rList) {
    allPoint <- rbind(allPoint, data.frame(
      x = 0,
      y = r,
      cos = 0,
      sin = 1
    ))
    for (i in 1:(nPoly - 1)) {
      degree <- 90 + degreeUnit * i
      x1 <- cos(degree * pi / 180) * r
      y1 <- sin(degree * pi / 180) * r
      allPoint <- rbind(allPoint, data.frame(
        x = x1,
        y = y1,
        cos = cos(degree * pi / 180),
        sin = sin(degree * pi / 180)
      ))
    }
  }
  return(allPoint)
}
getCutLine <- function(startPoint, len, perp) {
  if (perp[1] == 0 && perp[2] == 0) {
    stop("(0,0) vector cannot find a Perpendicular")
  } else if (perp[2] == 0) {
    if (perp[1] < 0) {
      return(c(startPoint[1] - len, startPoint[2]))
    }
    return(c(startPoint[1] + len, startPoint[2]))
  } else if (perp[1] == 0) {
    return(c(startPoint[1], startPoint[2] + len))
  } else{
    r <- perp[1] / perp[2]
  }
  #adjust <- abs(len/(perp[1]))
  adjust <- (len^2 / ((perp[1]^2) * (1 + (1 / r)^2)))^0.5
  result <-  c(perp[1] * adjust + startPoint[1] , perp[1] * adjust * (1 /
                                                                        r) + startPoint[2])
  return(result)
}
getPerpendicular <- function(v = NULL, changeSide = TRUE) {
  if (changeSide) {
    if (is.vector(v) && length(v) == 2) {
      if (v[1] == 0 && v[2] == 0) {
        stop("cannot find perp. with a point")
      } else if (v[1] == 0) {
        return(c(-1, 0))
      } else if (v[2] == 0) {
        return(c(0, -1))
      } else{
        return(c(-1, v[1] / v[2]))
      }
    } else{
      stop("generate perpendicular vector error, check data type and dimension.")
    }
  } else{
    if (is.vector(v) && length(v) == 2) {
      if (v[1] == 0 && v[2] == 0) {
        stop("cannot find perp. with a point")
      } else if (v[1] == 0) {
        return(c(1, 0))
      } else if (v[2] == 0) {
        return(c(0, 1))
      } else{
        return(c(1, -v[1] / v[2]))
      }
    } else{
      stop("generate perpendicular vector error, check data type and dimension.")
    }
  }
}
getCutDf <- function(tempDf, transMatrix, nP, indNum) {
  startDf <- data.frame(x = tempDf$cos,
                        y = tempDf$sin,
                        group = tempDf$group)
  perp1 <- lapply(
    1:nP,
    FUN = function(x)
      getPerpendicular(unlist(transMatrix[x, ]), changeSide = T)
  )
  perp2 <- lapply(
    1:nP,
    FUN = function(x)
      getPerpendicular(unlist(transMatrix[x, ]), changeSide = F)
  )
  
  cutPos1 <- sapply(
    1:(nP * indNum),
    FUN = function(x) {
      u <- x %% nP
      if (u == 0) {
        u <- nP
      }
      getCutLine(startDf[x, ], 0.025, perp1[[u]])
    }
  )
  cutPos2 <- sapply(
    1:(nP * indNum),
    FUN = function(x) {
      u <- x %% nP
      if (u == 0) {
        u <- nP
      }
      getCutLine(startDf[x, ], 0.025, perp2[[u]])
    }
  )
  #print(as.data.frame(t(cutPos1)))
  cutDf1 <- cbind(startDf, as.data.frame(t(cutPos1)))
  cutDf2 <- cbind(startDf, as.data.frame(t(cutPos2)))
  colnames(cutDf1) <- c("x1", "y1", "obsGroup", "x2", "y2")
  colnames(cutDf2) <- c("x1", "y1", "obsGroup", "x2", "y2")
  
  cutDf1$x2 <- as.numeric(cutDf1$x2)
  cutDf1$y2 <- as.numeric(cutDf1$y2)
  cutDf2$x2 <- as.numeric(cutDf2$x2)
  cutDf2$y2 <- as.numeric(cutDf2$y2)
  return(list(data.frame(cutDf1), data.frame(cutDf2)))
}
build3DRect <- function(len = NULL,
                        wid = NULL,
                        hei = NULL,
                        g = NULL) {
  if (is.null(g)) {
    g <- as.factor("g")
  }
  vertice <- get_vertice(3)
  vertice[c(3, 4, 7:8), 2] <- vertice[c(3, 4, 7:8), 2] + hei
  vertice[c(5:8), 1] <- vertice[c(5:8), 1] + wid
  vertice[c(2, 4, 6, 8), 3] <- vertice[c(2, 4, 6, 8), 3] + len
  vertice <- as.data.frame(vertice)
  vertice <- point3Dto2D(vertice)
  #rearrange
  vertice[, 6:11] <- 0
  vertice[c(1, 2, 4, 3), 6] <- paste0(g, 1)
  vertice[c(3, 4, 8, 7), 7] <- paste0(g, 2)
  vertice[c(5, 6, 8, 7), 8] <- paste0(g, 3)
  vertice[c(1, 2, 6, 5), 9] <- paste0(g, 4)
  vertice[c(1, 3, 7, 5), 10] <- paste0(g, 5)
  vertice[c(2, 4, 8, 6), 11] <- paste0(g, 6)
  d <- vertice[, c(4, 5)]
  d <- rbind(d[c(1, 2, 4, 3), ], d[c(3, 4, 8, 7), ], d[c(5, 6, 8, 7), ], d[c(1, 2, 6, 5), ], d[c(1, 3, 7, 5), ], d[c(2, 4, 8, 6), ])
  group <- matrix(c(vertice[, 6], vertice[, 7], vertice[, 8], vertice[, 9], vertice[, 10], vertice[, 11]),
                  ncol = 1)
  group <- group[group != 0]
  d <- cbind(d, group)
  d$group <- as.factor(d$group)
  return(d)
}
reRange <- function(min, max, data) {
  dist <- max - min
  return(data * dist - abs(min))
}
shift <- function(data, unit) {
  unit <- 1 + unit
  data$x <- round(data$x, 10)
  data$y <- round(data$y, 10)
  data$x <- data$x * unit
  data$y <- data$y * unit
  return(data)
}
