R/maxvenn.R

Defines functions .square.universe .default.SetLabelPositions .try.merge.faces.invisibly.split .merge.faces.invisibly.split joinEdgesInDrawing getEdge remove.nonintersectionpoints .rename.edge .check.duplicate.edges rename.node .check.clashes .nodes.identical .node.distance .add.intersection.points .node.number.unused .find.duplicate.point .find.point.in.nodelist .internal.edge.drawing.intersection .SplitFaceAtintersections .addIntersectingFace .probe.chord.intersections .create.edge.joining.faces .find.point.in.diagram .addNonintersectingFace .addSetWithExistingEdges addSetToDrawing injectPoints newTissueFromPolygon newTissueFromEllipse newTissueFromCircle injectEdge .find.face.containing.edge .points.of.face .is.face.within.set .is.point.within.face pnpolytest pnpoly injectPoint .edge.in.Drawing internalPointsofFaces .find.triangle.within.face .find.point.within.face .face.maxradius .find.point.on.face .PlotFaces.TissueDrawing .PlotFaceNames.TissueDrawing .PlotFace.TissueDrawing .face.centroid .polygon.centroid faceAreas .polygon.area .face.area .face.toxy .face.to.faceEdges .PlotSetBoundaries.TissueDrawing .VDPlotArcs .validateDrawing .validateFaces getFace deleteFace addFace .startFaceAtPoint spliceEdgeIntoFace renameFaces .faceEdgeClasses .faceEdgeNames setSignature updateSignature .faceSignatures .faceNames PlotDarkMatter makevp.eqsc PlotSetLabels .default.FaceLabelPositions PlotIntersectionText PlotVennGeometry SetColours SetTextColours FaceTextColours FaceColours VennThemes UpViewports CreateViewport spliceinstead .face.midplace .find.point.on.EdgeLines fequal .normalise.sector sector.to.xy .theta.to.point.xy .point.xy.to.theta .join.arcs .join.lines .removeDuplicates .find.linear.linear.intersection .find.linear.circle.intersection .find.linear.intersection .det2 .find.sector.sector.intersection newEdgeLines newEdgeSector .findIntersection make.E4 compute.E4 compute.C3 .pairwise.overlaps ThreeCircles .twoCircleIntersectionPointsObsolete .Venn.2.weighted.distance compute.C2 .circle.SetLabelPositions TwoCircles plot_Max_Venn .WeightUniverse .WeightVisible VennSetNames dark.matter.signature Weights VennSignature Indicator NumberOfSets VennFromSets_individual VennFromSets_group intersection Max_Venn

Documented in Max_Venn plot_Max_Venn

#main
#######################################################################
#'@export
setClass("Venn",
         representation( IndicatorWeight="matrix",IntersectionSets="list")
)
#'@title Function Max_Venn
#'@param Sets a setList of protein groups generated by function \code{\link{make_proteinGroups_setList}}()
#'@param IndividualAnalysis a boolean. If FALSE, conventional intersection analysis is performed; each protein group is treated as a single string from comparisons. If TRUE, individual proteins in each protein group are compared to others; each protein group is treated as a vector of individual string elements for comparisons.
#'@return an S4 class "Venn" object
#'@export
Max_Venn <- function(Sets,Weight,SetNames,numberOfSets,IndividualAnalysis) {
  if (!missing(Sets)) {
    if (is.null(names(Sets)) & !missing(SetNames)) {
      names(Sets) <- SetNames
    }
    if (IndividualAnalysis == FALSE) {
      return(VennFromSets_group(clean_list(Sets)))
    } else {
      return(VennFromSets_individual(clean_list(Sets)))
    }
  }
  if(missing(numberOfSets)) {
    numberOfSets <- if (missing(SetNames)) 0  else length(SetNames)
  }
  if (missing(SetNames)) {
    SetNames <- seq_len(numberOfSets)
  }


  if(numberOfSets==0) {
    Indicator <- matrix(nrow=0,ncol=0)
  } else {
    Indicator <- (data.matrix(do.call(expand.grid,lapply(seq(1,length=numberOfSets),function(x){c(0,1)}))))==1
  }
  rownames(Indicator) <- apply((Indicator),1,function(x){paste(as.numeric(x),collapse="")})
  colnames(Indicator) <- SetNames

  if(missing(Weight)) {
    Weight <- rep(1,nrow(Indicator))
  } else if( length(Weight) >0 & length(Weight) < nrow(Indicator) & is.null(names(Weight)) ) {
    stop("Weight length does not match number of intersections")
  }
  if (is.null(names(Weight))) {
    names(Weight) <- rownames(Indicator)
  }

  IndicatorWeight <- cbind(Indicator,.Weight=Weight[rownames(Indicator)])

  new("Venn",IndicatorWeight =IndicatorWeight )
}

#Function that extracts intersection of multiple vectors
#' @export
 intersection <- function(x, y, ...){
      if (missing(...)) intersect(x, y)
  else intersect(x, intersection(y, ...))
 }

#Function that calculates overlaps
#'@export
VennFromSets_group <- function(setList) {
  SetNames <- names(setList)
  if (is.null(SetNames)) { SetNames <- seq_along(setList) }
  VN <- Max_Venn(SetNames=SetNames)
  VIsig <- VennSignature(VN)
  IntersectionSets <- sapply(1:length(VIsig),function(x)NULL)
  names(IntersectionSets) <- VIsig
  universe <- NULL
  for (iset in setList) {
    universe <- union(universe,iset)
  }
  for (element in universe) {
    sig <- as.numeric(!is.na(sapply(setList,match,x=element)))
    sig <- paste(sig,collapse="")
    IntersectionSets[[sig]] <- union(IntersectionSets[[sig]],element)
  }
  Weights <- sapply(IntersectionSets,length)
  Vres <- Max_Venn(SetNames=SetNames,Weight=Weights)
  Vres@IntersectionSets <- IntersectionSets
  Vres
}
#If individual proteins within a protein group match, venn overlap is considered
#'@export
VennFromSets_individual <- function(setList) {
  SetNames <- names(setList)
  if (is.null(SetNames)) { SetNames <- seq_along(setList) }
  VN <- Max_Venn(SetNames=SetNames)
  VIsig <- VennSignature(VN)
 # VIsig <- c("000", "100" ,"010" ,"110", "001", "101", "011" ,"111")
  IntersectionSets <- sapply(1:length(VIsig),function(x)NULL)
  names(IntersectionSets) <- VIsig
  #Comparing sets from here
  #Internal function comparing overlaps
  overlap <- function(one_protein_group, sets_of_protein_groups) {
    #Convert a string of grouped proteins into a vector of individual protein components for each protein from the protein group selected for comparison
    proteins <- str_split(one_protein_group,"\\;")[[1]]
    nsets <- length(sets_of_protein_groups)
    indices <- vector(mode = "list", length = nsets)
    names(indices) <- names(sets_of_protein_groups)
    if_fullmatch <- FALSE
    #Intersect all sets!
    for (n in 1:nsets) {
      the_set <- sets_of_protein_groups[[n]]
      match_ID <- match(one_protein_group, the_set)
      fullmatch <- !is.na(match_ID)
      if (fullmatch) {
        indices[[n]] <- match_ID
        #Skip current iteration if it's a full match
        next
      } else {
        #Convert a string of grouped proteins into a list of vectors of individual protein components for each protein group from each set to be compared against
        the_set_split <- str_split(the_set,"\\;")
        #Compare to each group
        for (n_grps in 1:length(the_set)) {
          is_overlap <- (length(intersect(the_set_split[[n_grps]], proteins)) > 0)
          if (is_overlap) {
            #Save the index of matching protein group within the set
            indices[[n]] <- n_grps
            #Should do the second comparison may need a recursive function
            break
          } else {indices[[n]] <- 0}
        }
      }
    }
    return(indices)
  }
 # #Internal function comparing overlaps to remove data inflation
 # overlap2 <- function(one_protein_group, one_set_of_protein_groups) {
 #   proteins <- str_split(one_protein_group,"\\;")[[1]]
 #   proteins_from_set <- unlist(str_split(one_set_of_protein_groups,"\\;"))
 #   test <- length(intersect(proteins_from_set,proteins))
 #   condition <- test > 0
 #   if (condition) {return(TRUE)} else {return(FALSE)}
 # }
  #Internal function revising Venn field ID for each protein group
  rev_sig <- function(sig, sets, proteins)
  {
    nsets <- length(sets)
    if (nsets == 2) {
      return(sig)
    } else if (nsets == 3) {
      switch(sig,
             "110" = {
               if (length(intersection(sets[[1]],sets[[2]])) > 0) {
                 return(sig)
               } else if (length(intersection(sets[[1]],proteins)) > 0) {
                 return("100")
               } else if (length(intersection(sets[[2]],proteins))) {return("010")}
             },
             "101" = {
               if (length(intersection(sets[[1]],sets[[3]])) > 0) {
                 return(sig)
               } else if (length(intersection(sets[[1]],proteins)) > 0) {
                 return("100")
               } else if (length(intersection(sets[[3]],proteins))) {return("001")}
             },
             "011" = {
               if (length(intersection(sets[[2]],sets[[3]])) > 0) {
                 return(sig)
               } else if (length(intersection(sets[[2]],proteins)) > 0) {
                 return("010")
               } else if (length(intersection(sets[[3]],proteins))) {return("001")}
             },
             "111" = {
               if (length(intersection(sets[[1]],sets[[2]],sets[[3]])) > 0) {
                 return(sig)
               } else {
                 for (r_sig in c("110", "101", "011")) {
                   rr_sig <- rev_sig(r_sig, sets, proteins)
                   if (as.integer(rr_sig) == as.integer(r_sig)) {
                     return(r_sig)
                     break
                   }
                 }
                 for (r_sig in c("110", "101", "011")) {
                   rr_sig <- rev_sig(r_sig, sets, proteins)
                   if (as.integer(rr_sig) != 0) {
                     return(rr_sig)
                     break
                   }
                 }
               }
             },
             #default
             return("000")
      )

  } else if (nsets == 4) {
    switch(sig,
           "1100" = {
             if (length(intersection(sets[[1]],sets[[2]])) > 0) {
               return(sig)
             } else if (length(intersection(sets[[1]],proteins)) > 0) {
               return("1000")
             } else if (length(intersection(sets[[2]],proteins))){return("0100")}
           },
           "1010" = {
             if (length(intersection(sets[[1]],sets[[3]])) > 0) {
               return(sig)
             } else if (length(intersection(sets[[1]],proteins)) > 0) {
               return("1000")
             } else if (length(intersection(sets[[3]],proteins))){return("0010")}
           },
           "0110" = {
             if (length(intersection(sets[[2]],sets[[3]])) > 0) {
               return(sig)
             } else if (length(intersection(sets[[2]],proteins)) > 0) {
               return("0100")
             } else if (length(intersection(sets[[3]],proteins))){return("0010")}
           },
           "1110" = {
             if (length(intersection(sets[[1]],sets[[2]],sets[[3]])) > 0) {
               return(sig)
             } else {
             for (r_sig in c("1100", "1010", "0110")) {
               rr_sig <- rev_sig(r_sig, sets, proteins)
               if (as.integer(rr_sig) == as.integer(r_sig)) {
                 return(r_sig)
                 break
               }
             }
             for (r_sig in c("1100", "1010", "0110")) {
                 rr_sig <- rev_sig(r_sig, sets, proteins)
                 if (as.integer(rr_sig) != 0) {
                   return(rr_sig)
                   break
                 }
               }
             }
           },
           "1001" = {
             if (length(intersection(sets[[1]],sets[[4]])) > 0) {
               return(sig)
             } else if (length(intersection(sets[[1]],proteins)) > 0) {
               return("1000")
             } else if (length(intersection(sets[[4]],proteins))){return("0001")}
           },
           "0101" = {
             if (length(intersection(sets[[2]],sets[[4]])) > 0) {
               return(sig)
             } else if (length(intersection(sets[[1]],proteins)) > 0) {
               return("0100")
             } else if (length(intersection(sets[[4]],proteins))){return("0001")}
           },
           "1101" = {
             if (length(intersection(sets[[1]],sets[[2]],sets[[4]])) > 0) {
               return(sig)
             } else {
             for (r_sig in c("1100", "1001", "0101")) {
               rr_sig <- rev_sig(r_sig, sets, proteins)
               if (as.integer(rr_sig) == as.integer(r_sig)) {
                 return(r_sig)
                 break
               }}
             for (r_sig in c("1100", "1001", "0101")) {
                 rr_sig <- rev_sig(r_sig, sets, proteins)
                 if (as.integer(rr_sig) != 0) {
                   return(rr_sig)
                   break
                 }
               }
             }
           },
           "0011" = {
             if (length(intersection(sets[[3]],sets[[4]])) > 0) {
               return(sig)
             } else if (length(intersection(sets[[3]],proteins)) > 0) {
               return("0010")
             } else if (length(intersection(sets[[4]],proteins))){return("0001")}
           },
           "1011" = {
             if (length(intersection(sets[[1]],sets[[3]],sets[[4]])) > 0) {
               return(sig)
             } else {
             for (r_sig in c("1010", "1001", "0011")) {
               rr_sig <- rev_sig(r_sig, sets, proteins)
               if (as.integer(rr_sig) == as.integer(r_sig)) {
                 return(r_sig)
                 break
               }}
             for (r_sig in c("1010", "1001", "0011")) {
                 rr_sig <- rev_sig(r_sig, sets, proteins)
                 if (as.integer(rr_sig) != 0) {
                   return(rr_sig)
                   break
                 }
               }
             }
           },
           "0111" = {
             if (length(intersection(sets[[2]],sets[[3]],sets[[4]])) > 0) {
               return(sig)
             } else {
             for (r_sig in c("0101", "0011", "0110")) {
               rr_sig <- rev_sig(r_sig, sets, proteins)
               if (as.integer(rr_sig) == as.integer(r_sig)) {
                 return(r_sig)
                 break
               }}
             for (r_sig in c("0101", "0011", "0110")) {
                 rr_sig <- rev_sig(r_sig, sets, proteins)
                 if (as.integer(rr_sig) != 0) {
                   return(rr_sig)
                   break
                 }
               }
             }
           },
           "1111" = {
             if (length(intersection(sets[[1]],sets[[2]],sets[[3]],sets[[4]])) > 0) {
               return(sig)
             } else {
             for (r_sig in c("1110", "0111", "1011", "1101")) {
               rr_sig <- rev_sig(r_sig, sets, proteins)
               if (as.integer(rr_sig) == as.integer(r_sig)) {
                 return(r_sig)
                 break
                }
             }
             for (r_sig in c("1110", "0111", "1011", "1101")) {
                 rr_sig <- rev_sig(r_sig, sets, proteins)
                 rrr_sig <- rev_sig(rr_sig, sets, proteins)
                 if (as.integer(rrr_sig) == as.integer(rr_sig)) {
                   return(rr_sig)
                   break
                 }
             }
             for (r_sig in c("1110", "0111", "1011", "1101")) {
                 rr_sig <- rev_sig(r_sig, sets, proteins)
                 rrr_sig <- rev_sig(rr_sig, sets, proteins)
                 if (as.integer(rrr_sig) != 0) {
                   return(rrr_sig)
                   break
                 }
               }
             }
           },
           #default
           return("0000")
    )
   }
  }
  universe <- NULL
  for (iset in setList) {
    universe <- union(universe,iset)
  }
  for (element in universe) {
    #Check if it's a direct full overlap
    sig <- as.numeric(!is.na(sapply(setList,match,x=element)))
    sig_check <- ((Reduce("+", sig)) == length(setList))
   if (sig_check) {
    #If TRUE, write the group directly to the output
     sig <- as.numeric(!is.na(sapply(setList,match,x=element)))
     sig <- paste(sig,collapse="")
     IntersectionSets[[sig]] <- union(IntersectionSets[[sig]],element)
   } else {
     #Call the overlap function that returns the Venn Field ID for each protein group in the universe?
     indices <- overlap(element,setList)
     proteins <- str_split(element,"\\;")[[1]]
     #Compare indexed groups
     sets <- sapply(1:length(indices),function(x) NULL)
     names(sets) <- names(indices)
     for (x in 1:length(indices)){
       to_sets <- unlist(str_split(setList[[names(indices)[x]]][indices[[x]]],"\\;"))
       if (!is.null(to_sets)) {
        sets[[names(indices)[x]]] <- to_sets
       }
     }
     sig <- as.numeric(indices > 0)
     sig_check <- ((Reduce("+", sig)) == 1)
     sig <- paste(sig,collapse="")
     if (sig_check) {
     IntersectionSets[[sig]] <- union(IntersectionSets[[sig]],element)
     } else {
     #Revise Venn field ID
     sig <- rev_sig(sig, sets, proteins)
     IntersectionSets[[sig]] <- union(IntersectionSets[[sig]],element)
     }
   }
  }
  Weights <- sapply(IntersectionSets,length)
  Vres <- Max_Venn(SetNames=SetNames,Weight=Weights)
  Vres@IntersectionSets <- IntersectionSets
  Vres
}

setMethod("show","Venn",function(object){
  cat(sprintf("A Venn object on %d sets named\n",NumberOfSets(object)))
  cat(paste(VennSetNames(object),collapse=","),"\n")
  show(Weights(object))
})

#'@export
NumberOfSets <- function(object)
{ncol(object@IndicatorWeight)-1}
#'@export
Indicator <- function(object){
  object <- as(object,"Venn")
  object@IndicatorWeight[,-ncol(object@IndicatorWeight),drop=FALSE]}

#setGeneric("SetNames",function(object){standardGeneric("SetNames")})
#'@export
VennSignature<- function(object){
  ind <- Indicator(object)
  inn <- apply(ind,1,paste,collapse="")
  inn
}
#'@export
Weights <- function(object) {
  V <- as(object,"Venn")
  wght <- V@IndicatorWeight[,".Weight"]
  names(wght) <- VennSignature(V)
  wght
}
#'@export
"Weights<-" <- function(object,value) {
  V <- as(object,"Venn")
  VS <- VennSignature(V)
  if (is.null(names(value))) {
    names(value) <- VS
  }
  value <- value[match(VS,names(value))]
  object@IndicatorWeight[,".Weight"] <- as.numeric(value)
  object
}
#'@export
dark.matter.signature <- function(object) {
  V <- as(object,"Venn")
  VS <- VennSignature(V)
  VS[regexpr("1",VS)<0]
}

#'@export
VennSetNames <-  function(object) {cn <- colnames(object@IndicatorWeight);cn[cn!=".Weight"] }
#'@export
setMethod("[","Venn", function(x,i,j,...,drop) {
  if (!missing(i)) {
    stop("Can't subset on rows")
  }
  if (!missing(j)) {
    Indicator <- x@IndicatorWeight
    Signature <- apply(Indicator [,setdiff(colnames(Indicator ),".Weight")],1,paste,collapse="")
    Indicator.df <- data.frame(Indicator)
    Indicator.df$Signature <- Signature

    newIndicator <- aggregate(Indicator[,".Weight",drop=FALSE],
                              by=data.frame(Indicator[,j,drop=FALSE]),FUN=sum)
    for (col in setdiff(colnames(newIndicator ),".Weight")) {
      newIndicator [,col] <- as.numeric(as.character(newIndicator [,col])) # sigh
    }
    x@IndicatorWeight <- data.matrix(newIndicator)

    newIndicator.df <- newIndicator[,setdiff(colnames(newIndicator),".Weight")]
    newSignature <- apply(newIndicator.df,1,paste,collapse="")
    newIndicator.df <- data.frame(newIndicator.df)
    newIndicator.df$newSignature <- newSignature
    newIndicator.df

    IntersectionSets <- x@IntersectionSets
    if (length(IntersectionSets )>0) {
      dfm <- merge(newIndicator.df,Indicator.df)
      newsetNames <- split(dfm$Signature,dfm$newSignature)
      newIntersectionSets <- sapply(newsetNames,function(sigs)as.vector(do.call(c,IntersectionSets[sigs])))
      x@IntersectionSets <- newIntersectionSets
    }
  }
  x
})
#'@export
.WeightVisible <- function(V) {# excluding  elements not in any sets
  wght <- V@IndicatorWeight
  wghtsum <- apply(wght[,-ncol(wght)],1,sum)
  sum(wght[wghtsum>0,ncol(wght)])
}
#'@export
.WeightUniverse <- function(V) {
  wght <- Weights(V)
  sum(wght)
}

#'@title Function plot_Max_Venn
#'@param V an S4 class "Venn" object generated by \code{\link{Max_Venn}}()
#'@param doWeights a boolean. If TRUE, plots weighed Venn Diagram (shapes change according to ID numbers in fields). If FALSE, plots unweighed Venn Diagram.
#'@export
plot_Max_Venn <- function(V=Max_Venn("setList"),doWeights=TRUE,add=FALSE,
                          show=list(FaceText="weight",Faces=TRUE),
                          gpList){
  nSets <- NumberOfSets(V)
  if (nSets == 2) {
    venn_object <- compute.C2(V,doWeights)
  } else if (nSets == 3) {
    venn_object <- compute.C3(V)
  } else if (nSets == 4) {
    venn_object <- compute.E4(V)
  } else {
    stop("Not enough or too many sets")
  }

  if (!add) {
    grid.newpage()
  }
  PlotVennGeometry(venn_object,gpList=gpList,show=show)
}

#Venn module
#######################################################################
#Two sets
#'@export
TwoCircles <- function(r,d,V) {
  if (length(r) !=2 ) {
    if (length(r)==1 ) {
      r <- rep(r,2)
    } else {
      stop("Need two circle radii")
    }
  }
  # Two circles, radius r1 and r2, distance d apart
  centres <- matrix(c(-d/2,0,d/2,0),ncol=2,byrow=TRUE)
  VDC1 <- newTissueFromCircle(centres[1,],radius=r[1],Set=1);
  VDC2 <- newTissueFromCircle(centres[2,],radius=r[2],Set=2);
  TM <- addSetToDrawing (drawing1=VDC1,drawing2=VDC2,set2Name="Set2",remove.points=TRUE)
  V2 <- new("VennDrawing",TM,V)
  SetLabels <- .circle.SetLabelPositions(V2,radii=r,centres=centres)
  V2 <- VennSetSetLabels(V2,SetLabels)
  FaceLabels <- .default.FaceLabelPositions(V2)
  V2 <- VennSetFaceLabels(V2,FaceLabels)

  V2
}
#'@export
.circle.SetLabelPositions <- function(object,radii,centres){
  yscale <- diff(VisibleRange(object)[,2]);
  smidge <- 0.01*yscale
  xy <- centres
  abovebelow <- rep(1,NumberOfSets(object))
  if (NumberOfSets(object)==3) {
    abovebelow <- c(1,-1,-1)
  }
  xy[,2] <- xy[,2]+abovebelow*(radii+smidge)
  VLabels <- data.frame(Label=rep("unset",nrow(xy)),x=NA,y=NA,hjust=I("center"),vjust=I("bottom"))
  VLabels$vjust <- ifelse(abovebelow>0,"bottom","top")
  VLabels[,2:3] <- xy
  VLabels$Label <- VennSetNames(as(object,"Venn"))
  VLabels
}
#'@export
compute.C2 <- function(V,doWeights=TRUE) {
  doEuler=FALSE
  Vcalc <- V
  if(!doWeights) {
    if (!doEuler) {
      # want each area, even if empty
      wght <- Weights(Vcalc )
      wght <- 1+ 0*wght
      Weights(Vcalc ) <- wght
    } else {
      wght <- Weights(Vcalc )
      wght [wght !=0] <- c(3,2,2,1)[wght !=0]
      Weights(Vcalc ) <- wght
    }
  }
  dList <- .Venn.2.weighted.distance (Vcalc,doEuler) # returns radii of two circles and their distance
  r1 <- dList$r1;r2 <- dList$r2; d <- dList$d;
  C2 <- TwoCircles(r=c(r1,r2),d=d,V) # d in TwoCircles is distance of centre from origin
  C2 <- .square.universe(C2,doWeights)
  C2

}
#'@export
.Venn.2.weighted.distance <- function(V,doEuler) {
  if (NumberOfSets(V) != 2) {
    stop(sprintf("Wrong number of sets (%d) in .Venn.2.weighted.distance",NumberOfSets(V)))
  }
  # cf Chow and Ruskey, 200?
  Weight <- Weights(V)
  wab <- Weight["00"] #not used
  wAb <- as.numeric(Weight["10"])
  waB <- as.numeric(Weight["01"])
  wAB <- as.numeric(Weight["11"])

  inneroff <- 1 # set = 2 to put inner circles completely inside
  outeroff <- 1.01 # =1 to have exact adjacency
  r1 <- sqrt( (wAb+wAB)/pi)
  r2 <- sqrt( (waB+wAB)/pi) # area proportional to weights

  if (wAb==0) { #inside the other one
    if (doEuler) {
      d <- (r2-r1)/inneroff
    } else { # bodge it outside to ensure the Venntersection..doesnt really make much sense
      d <- (r2-r1)+0.1*r1
    }
  } else if (waB==0) { # also
    if (doEuler) {
      d <- (r1-r2)/inneroff
    } else { # bodge it outside to ensure the Venntersection..doesnt really make much sense
      d <- (r1-r2)+0.1*r1
    }
  } else if (wAB==0) {
    d <- outeroff *  (r1+r2)  # no intersection
    if (!doEuler) {
      d <- 0.95 * d
    }

  } else  { # all nonzero
    alpha  <- function(d,r1,r2) {
      alphaD <- (d^2+r1^2-r2^2)
      alphaD <- ifelse(alphaD ==0,alphaD ,alphaD / (2 * r1 * d) )
      alphaD <- ifelse(alphaD>1,1,alphaD)
      alphaD <- ifelse(alphaD< -1,-1,alphaD)
      alpha <-  2 *acos( alphaD )
      alpha
    }
    sigma <- function(d,r1,r2) {
      alpha <- alpha(d,r1,r2)
      betaD <- (d^2+r2^2-r1^2);
      betaD <- ifelse(betaD==0,betaD,betaD/ (2 * r2 * d) )
      betaD <- ifelse(betaD< (-1),-1,betaD )
      betaD <- ifelse(betaD> 1,1,betaD )
      beta <-   2 *acos( betaD )
      sigma <- 0.5 * r1^2*(alpha-sin(alpha))+ 0.5 * r2^2 * (beta-sin(beta))
      sigma
    }
    sigmaminuswAB <- function(d,r1,r2,wAB) {
      sigma(d,r1,r2) - wAB
    }
    d <-	uniroot(sigmaminuswAB ,lower=r1-r2,upper=r1+r2,r1=r1,r2=r2,wAB=wAB)$root
  } # wAB != 0
  list(r1=r1,r2=r2,d=d )

}
#'@export
.twoCircleIntersectionPointsObsolete <- function(r,xy,i1=1,i2=2) {
  r <- r[c(i1,i2)]
  xy <- xy[c(i1,i2),]
  # two circles with radius r[1], r[2], centres xy[1,], xy[2,]
  d <- sqrt(sum((xy[1,]-xy[2,])^2))
  # do they intersect?
  if (r[1]+r[2] > d  & d > abs(r[1]-r[2])) {
    d1 <- (d^2-r[2]^2+r[1]^2)/(2*d)
    d2 <- abs(d - d1)
    xyvec <- xy[2,] - xy[1,]
    midchord <- xy[1,] + (d1/d)*xyvec
    normal <- c(-xyvec[2],xyvec[1])
    normal <- normal/sqrt(sum(normal^2))
    halfchord <-  sqrt(r[1]^2-d1^2)
    p1 <- midchord + (halfchord)*normal
    p2 <- midchord - (halfchord)*normal
    p12 <- rbind(p1,p2)
  } else {
    p12 <- matrix(NA,nrow=2,ncol=2)
  }
  rownames(p12) <- paste("p",i1,i2,c("a","b"),sep="")
  p12
}
#Three sets
#'@export
ThreeCircles <- function(r,x,y,d,angles,V) {
  if (missing(x) | missing(y)) {
    if (missing(d)) {
      stop("Need x and y or d")
    }
    if (missing(angles)) {
      angles <- pi/2-c( 0, 2*pi/3, 4 * pi/3)
    }
    x <- d*cos(angles)
    y <- d*sin(angles)
  }
  if (length(r) !=3 ) {
    if (length(r)==1 ) {
      r <- rep(r,3)
    } else {
      stop("Need three circle radii")
    }
  }

  centres <- matrix(c(x,y),ncol=2,byrow=FALSE)

  nodes <- 1; TM <- NA
  while (!inherits(TM,"TissueDrawing") & nodes < 10) {
    VDC1 <- newTissueFromCircle(centres[1,],radius=r[1],Set=1,nodes=nodes);
    VDC2 <- newTissueFromCircle(centres[2,],radius=r[2],Set=2,nodes=nodes);
    TM <- addSetToDrawing (drawing1=VDC1,drawing2=VDC2,set2Name="Set2")
    nodes <- nodes+1
  }
  if (nodes>=10) stop("Can't join circles")
  nodes <- 1; TM2 <- NA
  while (!inherits(TM2,"TissueDrawing")  & nodes < 10) {
    VDC3 <- newTissueFromCircle(centres[3,],radius=r[3],Set=3,nodes=nodes);
    TM2 <- addSetToDrawing (drawing1=TM,drawing2=VDC3,set2Name="Set3")
    nodes <- nodes+1
  }
  if (nodes>=10) stop("Still can't join circles")

  C3 <- new("VennDrawing",TM2,V)
  SetLabels <- .circle.SetLabelPositions(C3,radii=r,centres=centres)
  C3 <- VennSetSetLabels(C3,SetLabels)
}
#'@export
.pairwise.overlaps <- function(V) {
  VI <- Indicator(V)
  VIsum <- apply(VI,1,sum)
  Vpairs <- unique(VI[VIsum==2,])
  Vwhich <- which(Vpairs==1,arr.ind=TRUE)
  Vindex <- Vpairs
  Vindex [Vwhich] <- Vwhich[,2]
  isdisjoint <- function(vrow) {
    vsub <- V[,vrow]
    vsum <- apply(Indicator(vsub),1,sum)
    overweight <- Weights(vsub)[vsum==2]
    overweight==0
  }
  Vpairs <- data.frame(Vpairs,check.names=FALSE)
  Vpairs$Disjoint <- apply(Vindex,1,isdisjoint)
  Vpairs
}
#'@export
compute.C3 <- function(V) {
  doWeights <- FALSE
  doEuler <- FALSE
  if (doWeights) {
    overlaps <- .pairwise.overlaps(V)
    dList12 <- .Venn.2.weighted.distance (V[,c(1,2)],doEuler ) # returns radii of two circles and their distance
    dList23 <- .Venn.2.weighted.distance (V[,c(2,3)],doEuler ) #
    dList31 <- .Venn.2.weighted.distance (V[,c(3,1)],doEuler ) #

    disjointcount <- sum(overlaps$Disjoint)
    dp <- c( cp= dList12$d, b = dList23$d, a = dList31$d)
    smidge <- 1 - 1e-4
    if (disjointcount==3) {
      # all disjoint, arrange with centres in equilateral triangle
      dmax <- max(dp)
      dp <- dp*0+dmax
    } else if (disjointcount==2) {
      #one is disjoint from both the others
      # set it at the same distance from both
      # and far enough that it will be a triangle
      conjoint <- overlaps[!overlaps$Disjoint,-ncol(overlaps)]
      conjointix <-  ( which(conjoint==0)%%3 +1)
      conjointdistance <-  dp[conjointix ]
      disjointdistances <- dp[-conjointix]
      disjointdistances <- max(disjointdistances,conjointdistance/2)
      dp[-conjointix] <- disjointdistances
    } else if (disjointcount==1) {
      # only one missing intersection; we set its distance to
      # force a (near) straightline
      # nb this will still fail if the intersections are large enough
      disjoint <- overlaps[overlaps$Disjoint,-ncol(overlaps)]
      disjointix <- ( which(disjoint ==0)%%3 +1)
      conjointdistances <-  dp[-disjointix ]
      dp[disjointix] <- sum(conjointdistances)*smidge
    }
    cp= dp["cp"]; b = dp["b"]; a=dp["a"]

    # can we satisfy the triangle inequality? if not, bodge it
    if (a+b < cp) {
      cp <-  (a+b)*smidge
    }
    if (b+cp < a) {
      a <-  (b+cp)*smidge
    }
    if (cp+a < b ) {
      b <- (cp+a)*smidge
    }
    # pick a centre for the first one
    c1 <- c(0, dList12$r1)
    # then place the others
    if (a==0 || b==0 || cp==0) {
      o21 <- cp *c(1,0) ; o31 <- a * c(0,1)
    } else {
      # use the SSS rule to compute angles in the triangle
      CP <- acos( (a^2+b^2-cp^2)/(2*a*b))
      B <- acos( (a^2+cp^2-b^2)/(2*a*cp))
      A <- acos( (cp^2+b^2-a^2)/(2*b*cp))
      # arbitrarily bisect one and calculate xy offsets from first centre
      theta <- B/2
      o21 <- cp * c( sin(theta), - cos(theta))
      o31 <- a * c( -sin(B-theta),	-cos(B-theta))
    }
    c2 <- c1 + o21
    c3 <- c1 + o31
    C3 <- ThreeCircles(r=c(dList12$r1,dList12$r2,dList31$r1),
                       x=c(c1[1],c2[1],c3[1]),y=c(c1[2],c2[2],c3[2]),V=V)
  } else {
    C3 <- ThreeCircles(r=0.6,d=0.4,V=V)
  }
  C3 <- .square.universe(C3,doWeights=doWeights)
  FaceLabels <- .default.FaceLabelPositions(C3)
  C3 <- VennSetFaceLabels(C3,FaceLabels)

  C3
}

#Four sets
#'@export
compute.E4 <- function(V,doWeights=FALSE,s=.25,dx=0.2) {
  if (doWeights) { warning("Cant do a weighted E4") }
  if (NumberOfSets(V) != 4) { stop("fournotfour")}
  env <- new.env()
  loaded <- data(ellipses,envir=env)
  if (!("ellipses" %in% loaded))
  {ellipses <- make.E4}
    TM <- ellipses
  VD <- new("VennDrawing",TM,V)
  SetLabels <- .default.SetLabelPositions(VD)
  VD <- VennSetSetLabels(VD,SetLabels)
  FaceLabels <- .default.FaceLabelPositions(VD)
  VD <- VennSetFaceLabels(VD,FaceLabels)
  VD <- .square.universe(VD,doWeights)
  VD

}
#'@export
make.E4 <- function(dx=0.02) {
  phi <- 0.8; dex <- 1.5;dey <- 2.5; a<- 7.6; e<- 0.9
  x0 <- c( -0.9, -5.0)
  VE <- list()
  VE[[1]] <- newTissueFromEllipse (x0+c(0,0),-phi ,e,-a,Set=1,dx=dx)
  VE[[2]] <- newTissueFromEllipse (x0+c(dex,0),phi ,e,a,Set=2,dx=dx)
  VE[[3]] <- newTissueFromEllipse (x0+c(-dey,dey),-phi ,e,-a,Set=3,dx=dx)
  VE[[4]] <- newTissueFromEllipse (x0+c(dex+dey,dey),phi ,e,a,Set=4,dx=dx)

  TM <- VE[[1]]
  for (ix in 2:4) {
    TM <- addSetToDrawing(TM,VE[[ix]],set2Name=paste("Set",ix,sep=""))
  }
  TM
}


#Graphics module1
#######################################################################

#'@export
setGeneric("PlotSetBoundaries",function(drawing,gp){standardGeneric("PlotSetBoundaries")})
#'@export
setGeneric("PlotNodes",function(drawing,gp){standardGeneric("PlotNodes")})
#'@export
setGeneric("PlotFaces",function(drawing,faceNames,gp,arrow,colourAlgorithm){standardGeneric("PlotFaces")})


#Graphics module2
#######################################################################
#'@export
setClass("VDedgeDrawn",representation(from="character",to="character",visible="logical",bb="matrix"),
         prototype(from=character(0),to=character(0),visible=TRUE))

## these generics have methods for all edge types inheriting from VDedgeDrawn
# called only within this file and documentation vignette
#'@export
setGeneric(".identical",function(edge1,edge2){standardGeneric(".identical")})
#'@export
setGeneric(".reverseEdge",function(edge){standardGeneric(".reverseEdge")})
#'@export
setGeneric(".midpoint",function(edge)standardGeneric(".midpoint"))
#'@export
setGeneric(".checkPointOnEdge",function(edge,point.xy)standardGeneric(".checkPointOnEdge"))
#'@export
setGeneric(".splitEdgeAtPoint",function(edge,point.xy)standardGeneric(".splitEdgeAtPoint"))
#'@export
setGeneric(".findIntersectionByType",function(edge1,edge2){standardGeneric(".findIntersectionByType")})
#'@export
setGeneric(".edge.to.xy",function(edge,dx){standardGeneric(".edge.to.xy")})

#'@export
setClass("VDedgeSector",representation("VDedgeDrawn",
                                       radius="numeric",fromTheta="numeric",toTheta="numeric",centre="numeric",hand="numeric"))
#'@export
setClass("VDedgeLines",representation("VDedgeDrawn",xy="matrix"))

#'@export
setMethod("show","VDedgeDrawn",function(object) {
  res <- c(from=object@from,to=object@to,visible=object@visible)
  show(res)
  invisible(	object)
})

#'@export
setMethod("show","VDedgeSector",function(object) {
  show(as(object,"VDedgeDrawn"))
  res <- c(centre=paste(object@centre,collapse=","),
           radius=object@radius,fromTheta=object@fromTheta,toTheta=object@toTheta,hand=object@hand)
  show(res)
  invisible(	object)
})

#'@export
setMethod(".identical",c("VDedgeSector","VDedgeSector"), function(edge1,edge2) {
  fequal(edge1@radius,edge2@radius) &
    fequal(edge1@fromTheta,edge2@fromTheta) &
    fequal(edge1@toTheta,edge2@toTheta) &
    all(fequal(edge1@centre,edge2@centre)) &
    fequal(edge1@hand,edge2@hand)
})
#'@export
setMethod(".identical",c("VDedgeLines","VDedgeLines"), function(edge1,edge2) {
  if (nrow(edge1@xy) != nrow(edge2@xy)) return(FALSE)
  all(fequal(edge1@xy,edge2@xy))
})
#'@export
setMethod(".identical",c("VDedgeSector","VDedgeLines"), function(edge1,edge2) {
  return(FALSE)
})
#'@export
setMethod(".identical",c("VDedgeLines","VDedgeSector"), function(edge1,edge2) {
  return(FALSE)
})
#'@export
.findIntersection<- function(edge1,edge2) {
  bb1 <- edge1@bb; bb2 <- edge2@bb;	smudge <-  (.Machine$double.eps ^ 0.5)

  x1 <- bb1[,1]; x2 <- bb2[,1]
  xok <- x2[2] >= x1[1] - smudge & x2[1] <= x2[2] +smudge
  y1 <- bb1[,2]; y2 <- bb2[,2]
  yok <- y2 [2] >= y1 [1] - smudge & y1 [1] <= y2 [2] +smudge
  if (xok & yok) {
    found <- .findIntersectionByType(edge1,edge2)
  } else {
    found <- matrix(ncol=2,nrow=0)
  }
  found
}

#'@export
newEdgeSector <- function(centre,hand=1,from,to,fromTheta,toTheta,radius,visible=TRUE) {
  if (missing (from)) { from <- "p1" }
  if (missing (to)) if ( fequal( (fromTheta-toTheta) %% (2 * pi),0)) { to <- from } else { to <- "p2"}
  bb <- rbind( centre-radius,centre+radius)
  lh <- new("VDedgeSector",centre=centre,hand=hand,from=from,to=to,fromTheta=fromTheta,toTheta=toTheta,radius=radius,visible=visible,bb=bb)
  lh
}
#'@export
newEdgeLines <- function(from,to,xy,visible=TRUE) {
  bb <- rbind(apply(xy,2,min),apply(xy,2,max))
  lh  <- new("VDedgeLines",from=from,to=to,xy=xy,visible=visible,bb=bb)
  lh
}


#'@export
setMethod("show","VDedgeLines",function(object) {
  show(as(object,"VDedgeDrawn"))
  res <- c(npoints=nrow(object@xy))
  show(res)
  invisible(	object)
})

#'@export
.find.sector.sector.intersection <- function(edge1,edge2) {
  r1 <- edge1@radius
  r2 <- edge2@radius
  centre.diff <- edge2@centre - edge1@centre
  d <- sqrt(sum(centre.diff^2))
  if (d > (r1+ r2)) { # disjoint
    intersectionPoints  <- (matrix(numeric(0),ncol=2))
  } else if (d < abs(r1-r2)) { # one inside the other
    intersectionPoints  <- (matrix(numeric(0),ncol=2))
  } else if (d == abs(r1-r2)) { # one inside, tangent touching
    p1 <- matrix((edge1@centre+ r1*(r1-r2)*centre.diff/d^2),ncol=2) # from simplification of below
    rownames(p1)<-"i1"
    intersectionPoints  <- (p1)
  } else if (d == (r1+r2)) { # adjacent, tangent touching
    p1 <- matrix((edge1@centre+ (r1/(r1+r2))*centre.diff),ncol=2) #
    rownames(p1)<-"i1"
    intersectionPoints  <- (p1)
  } else { # two circles intersect in two points
    if (d==0 & r1==r2){stop("Identical circles")}
    d1 <- (d^2 - r2^2+ r1^2) /( 2* d)
    d2 <- d - d1
    # half-height from the chord to the intersection
    yh <- (1/(2*d))* sqrt(4*d^2*r1^2-(d^2-r2^2+r1^2)^2)

    dvec <- centre.diff/d # normalised vector from 1 to 2
    nvec <- c(-dvec[2],dvec[1]) # normal to that
    p1 <- matrix(edge1@centre + (d1)*dvec + yh * nvec,ncol=2);rownames(p1)<-"i1"
    p2 <- matrix(edge1@centre + (d1)*dvec - yh * nvec,ncol=2);rownames(p2)<-"i2"
    if (yh==0) {
      intersectionPoints  <- p1
    } else {
      intersectionPoints  <- (rbind(p1,p2))
    }
  }
  if (nrow(intersectionPoints)>0) {
    onedge1 <- sapply(seq_len(nrow(intersectionPoints  )),function(ix){
      .checkPointOnEdge(edge1,intersectionPoints  [ix,,drop=FALSE])})
    onedge2 <- sapply(seq_len(nrow(intersectionPoints  )),function(ix){
      .checkPointOnEdge(edge2,intersectionPoints  [ix,,drop=FALSE])})

    intersectionPoints <- intersectionPoints [onedge1 & onedge2 ,,drop=FALSE]
  }
  dimnames(intersectionPoints) <- NULL

  intersectionPoints
}
#'@export
setMethod(".findIntersectionByType",c("VDedgeSector","VDedgeSector"), .find.sector.sector.intersection)
#'@export
.det2 <- function(m) { m[1,1] * m[2,2] - m[1,2]* m[2,1] }
#'@export
.find.linear.intersection <- function(xy1,xy2) {

  # See Mathworld line-line intersection

  denommat <- .det2(rbind( xy1[1,]-xy1[2,],  xy2[1,]-xy2[2,]))
  if (fequal(0,denommat)) { # parallel
    # it may still be colinear, but in that case we choose to describe this as no intersection,
    # as the endpoints of the edges will also be in other edges which won't be colinear with one of them
    #p1 <- xy1[1,];
    #p2 <- xy1[2,];
    #p3 <- xy2[1,]
    #detm <- p1[1]*(p2[2]-p3 [2])+p2[1]*(p3 [2]-p1[2])+p3 [1]*(p1[2]-p2[2])
    # no, so no intersection
    #if (!fequal(0,denommat)) {
    return(c(NA,NA))
    #}
  }
  xm <- .det2( matrix( c(.det2(xy1) , xy1[1,1]-xy1[2,1],.det2(xy2), xy2[1,1]-xy2[2,1]),nrow=2,byrow=TRUE))/denommat
  ym <- .det2( matrix( c(.det2(xy1) , xy1[1,2]-xy1[2,2],.det2(xy2), xy2[1,2]-xy2[2,2]),nrow=2,byrow=TRUE))/denommat

  # parameter s1 goes from 0 to 1 from first to second point

  if (!fequal(xy1[2,1]-xy1[1,1],0)) {
    s1 <- (xm - xy1[1,1])/(xy1[2,1]-xy1[1,1]);
  } else {
    s1 <- (ym - xy1[1,2])/(xy1[2,2]-xy1[1,2]);
  }
  if (!fequal(xy2[2,1]-xy2[1,1],0)) {
    s2 <- (xm - xy2[1,1])/(xy2[2,1]-xy2[1,1])
  } else {
    s2 <- (ym - xy2[1,2])/(xy2[2,2]-xy2[1,2])
  }
  smudge <-  (.Machine$double.eps ^ 0.5)

  if ( s1< 0-smudge | s1> 1 +smudge | s2 < 0-smudge | s2 > 1+smudge) {
    return(c(NA,NA))
  } else {
    return(c(xm,ym))
  }


}
#'@export
.find.linear.circle.intersection <- function(xy,sector) {
  intersectionPoints <- matrix(nrow=0,ncol=2)
  xr <- sector@centre[1]; yr <- sector@centre[2]
  r <- sector@radius

  # line is y=mx+c
  m <- ( xy[2,2] - xy[1,2] )/(xy[2,1] - xy[1,1])
  if (is.infinite(m)) { # must be easier way than special casing eg x<->y
    v <- as.numeric(xy[1,1]) # vertical line at x=v
    if ( v <  xr - r | v > xr + r ) {
      return(intersectionPoints)
    }
    if ( v== xr - r) {
      intersectionPoints <- rbind(intersectionPoints,c(xr-r,yr))
      return(intersectionPoints)
    }
    if (v == xr+r ) {
      intersectionPoints <- rbind(intersectionPoints,c(xr+r,yr))
      return(intersectionPoints)
    }
    hoff <- sqrt(r*r - (xr-v)^2)
    intersectionPoints <- rbind(intersectionPoints,c(v,yr+hoff))
    intersectionPoints <- rbind(intersectionPoints,c(v,yr-hoff))
    return(intersectionPoints)
  }



  cc <-  xy[1,2] - m * xy[1,1]
  # circle is (x-xr)^2+(y-yr)^2 = r^2
  # (x-xr)^2 + (mx+c-yr)^2 = r^2
  # x^2(1+m^2) + 2 x (m*c-m*yr-xr) + xr^2 + (c-yr)^2 - r^2 = 0

  qa <- (1+m^2)
  qb <- 2 * (m *cc - m * yr - xr)
  qc <- xr^2 + (cc-yr)^2 - r^2


  det <- (qb*qb - 4 * qa* qc)
  if (det <0) { }
  if (det ==0) {
    x0 <- (-qb/(2*qa))
    y0 <- m * x0 + cc
    intersectionPoints <- rbind(intersectionPoints,c(x0,y0))
  }
  if (det >0) {
    x1 <- (-qb + sqrt(det))/(2*qa)
    x2 <- (-qb - sqrt(det))/(2*qa)
    y1 <- m * x1 + cc
    y2 <- m * x2 + cc
    intersectionPoints <- rbind(intersectionPoints,c(x1,y1))
    intersectionPoints <- rbind(intersectionPoints,c(x2,y2))
  }
  intersectionPoints
}

#'@export
setMethod(".findIntersectionByType",c("VDedgeLines","VDedgeSector"), function(edge1,edge2) {
  # first find all the intersection points assuming infinite line and complete circle
  intersectionPoints <- matrix(nrow=0,ncol=2)
  for(i1 in 1:(nrow(edge1@xy)-1)) {
    ict <-.find.linear.circle.intersection(xy=edge1@xy[i1:(i1+1),],sector=edge2)
    if (nrow(ict)>0) {
      intersectionPoints <- rbind(intersectionPoints,ict)
    }
  }
  intersectionPoints <- .removeDuplicates(intersectionPoints )
  if (nrow(intersectionPoints)>0) {
    onedge1 <- sapply(seq_len(nrow(intersectionPoints)),function(ix){
      .checkPointOnEdge(edge1,intersectionPoints[ix,,drop=FALSE])})
    onedge2 <- sapply(seq_len(nrow(intersectionPoints)),function(ix){
      .checkPointOnEdge(edge2,intersectionPoints[ix,,drop=FALSE])})
    intersectionPoints <- intersectionPoints [onedge1 & onedge2 ,,drop=FALSE]
  }
  dimnames(intersectionPoints) <- NULL
  intersectionPoints
}
)
#'@export
setMethod(".findIntersectionByType",c("VDedgeSector","VDedgeLines"), function(edge1,edge2).findIntersectionByType(edge2,edge1))
#'@export
.find.linear.linear.intersection <-  function(edge1,edge2) {
  intersectionPoints <- matrix(nrow=0,ncol=2)
  for(i1 in 1:(nrow(edge1@xy)-1)) {
    for (i2 in 1:(nrow(edge2@xy)-1)) {
      ict <-.find.linear.intersection(xy1=edge1@xy[i1:(i1+1),],xy2=edge2@xy[i2:(i2+1),])
      if (!any(is.na(ict))) {
        intersectionPoints <- rbind(intersectionPoints,ict)
      }
    }
  }
  intersectionPoints <- .removeDuplicates(intersectionPoints )
  intersectionPoints
}
#'@export
setMethod(".findIntersectionByType",c("VDedgeLines","VDedgeLines"),.find.linear.linear.intersection)
#'@export
.removeDuplicates <- function(xypoints) {
  if (nrow(xypoints)<2) {return(xypoints)}
  for (ix in 1:(nrow(xypoints)-1)) {
    for (jx in (ix+1):nrow(xypoints)) {
      #cat(ix,jx,"\n")
      #show(xypoints)
      if (!any(is.na(xypoints[c(ix,jx),1]))) {
        dist2 <- sum((xypoints[ix,]-xypoints[jx,])^2)
        if (dist2 < .Machine$double.eps ) {
          xypoints[jx,] <- NA
        }
      }
    }
  }
  xypoints <- xypoints[!is.na(xypoints[,1]),,drop=FALSE]
}

#'@export
setGeneric("joinEdges",function(object1,object2)standardGeneric("joinEdges"))
#'@export
setMethod("joinEdges",c("VDedgeLines","VDedgeLines"),function(object1,object2).join.lines(object1,object2))
.join.lines <- function(object1,object2) {
  # assumes they do join!
  visibility <- c(object1@visible,object2@visible);stopifnot(visibility[1]==visibility[2])
  xy <- rbind(object1@xy,object2@xy[-1,,drop=FALSE])
  newEdge <- newEdgeLines(from=object1@from,to=object2@to,visible=visibility[1],xy=xy)
  newEdge
}
#'@export
setMethod("joinEdges",c("VDedgeSector","VDedgeSector"),function(object1,object2).join.arcs(object1,object2))
.join.arcs <- function(object1,object2) {
  # assumes they do join and have same radius centre and hand (and as a side effect will have the same bb)
  visibility <- c(object1@visible,object2@visible);stopifnot(visibility[1]==visibility[2])
  if (!fequal((object1@toTheta - object2@fromTheta) %% (2 * pi),0)) {
    stop(sprintf("Sectors joined at different thetas %g %g\n",object1@toTheta, object2@fromTheta))
  }
  if (object1@toTheta <= 0 & object2@fromTheta > 0 ) {
    object2@fromTheta <- object2@fromTheta - 2*pi # not used but you get the idea
    object2@toTheta <- object2@toTheta - 2 *pi
  }
  newEdge <- object1;
  newEdge@toTheta <- object2@toTheta
  newEdge@to <- object2@to
  newEdge
}
#'@export
.point.xy.to.theta <- function(point,centre) {
  pointCentre <- as.numeric(point)-centre
  theta <- atan2(pointCentre[2],pointCentre[1])
  #	theta <- -theta
  theta <- theta %% ( 2* pi)
}
#'@export
.theta.to.point.xy <- function(theta,r,centre) {
  #	theta <- -theta
  x <- r* cos(theta)+centre[1];y <- r*sin(theta)+centre[2]
  cbind(x,y)
}
#'@export
sector.to.xy <-  function(edge,dx=.05) {
  r <- edge@radius;
  hand <- edge@hand
  thetafrom <- edge@fromTheta;thetato <- edge@toTheta
  # if hand > 0 we always go anti-clockwise, decreasing thetafrom
  # so thetato must be less  than thetafrom
  if (hand>0) {
    if (thetato>thetafrom)  { thetato <- thetato - 2* pi }
    thetadist <- thetafrom - thetato
  }
  else {
    if (thetato<thetafrom)  { thetato <- thetato + 2* pi }
    thetadist <- thetato - thetafrom
  }
  arclength <- (thetadist) * r
  nintervals <- max(3,arclength/dx)
  theta <- seq(from=thetafrom,to=thetato,length=nintervals)
  xy <- .theta.to.point.xy(theta,r,edge@centre)
}
#'@export
.normalise.sector <- function(edge) {
  # we guarantee 2pi>from>0 and from>to>-2pi
  stopifnot(edge@fromTheta>=0 & edge@fromTheta<=2*pi)
  if (edge@toTheta>edge@fromTheta) {
    edge@toTheta <- edge@toTheta- (2*pi)
  }
  stopifnot(edge@fromTheta>=edge@toTheta & edge@toTheta>=-2*pi)
  edge
}
#'@export
setMethod(".edge.to.xy",c("VDedgeSector","numeric"),
          function(edge,dx){sector.to.xy(edge)})
#'@export
setMethod(".edge.to.xy",c("VDedgeSector","missing"),
          function(edge,dx){sector.to.xy(edge)})
#'@export
setMethod(".edge.to.xy",c("VDedgeLines","numeric"),
          function(edge,dx) {	edge@xy})
#'@export
setMethod(".edge.to.xy",c("VDedgeLines","missing"),
          function(edge,dx) {edge@xy})

#'@export
setMethod(".reverseEdge","VDedgeLines",function(edge){
  edge@xy <- edge@xy[ rev(seq_len(nrow(edge@xy))),]
  temp <- edge@from
  edge@from <- edge@to
  edge@to <- temp
  edge
})
#'@export
setMethod(".reverseEdge","VDedgeSector",function(edge){
  edge@hand <- - edge@hand
  temp <- edge@from
  edge@from <- edge@to
  edge@to <- temp
  temp <- edge@fromTheta
  edge@fromTheta<- edge@toTheta
  edge@toTheta <- temp
  edge
})

#'@export
setMethod(".checkPointOnEdge",c("VDedgeSector"),function(edge,point.xy) {
  r <- edge@radius
  rp <- sqrt( sum( (point.xy - edge@centre)^2))
  theta <- .point.xy.to.theta(point.xy,edge@centre)
  if (edge@from==edge@to) {
    intheta <- TRUE
  } else {
    if (edge@toTheta>=0) {
      intheta <- (edge@fromTheta >= theta & theta >= edge@toTheta)
    } else {
      #			intheta <- (0<=theta & theta <= edge@fromTheta ) | ( 2*pi+edge@toTheta <= theta & theta <= 2*pi)
      intheta <- ( edge@fromTheta >= theta) | ( 2*pi+edge@toTheta <= theta )
    }
    if (edge@hand<0) intheta <- !intheta
  }
  intheta & isTRUE( all.equal(r,rp))

}
)
#'@export
fequal <- function(x,y) {
  abs(x-y) < (.Machine$double.eps ^ 0.5)
}
#'@export
.find.point.on.EdgeLines <- function(edge,point.xy) {
  ison <- FALSE
  for (nix in 1:(nrow(edge@xy)-1)) {
    line <- edge@xy[c(nix,nix+1),]
    p1 <- line[1,];
    p2 <- line[2,];
    # first check if points are colinear
    detm <- p1[1]*(p2[2]-point.xy[2])+p2[1]*(point.xy[2]-p1[2])+point.xy[1]*(p1[2]-p2[2])
    if(fequal(0,detm)) {
      # then that point is on segment
      # is it vertical? if so choose y
      if ( fequal(p1[1],p2[1]) && fequal(point.xy[1],p1[1])) {
        s <- ( point.xy[2]-p1[2])/(p2[2]-p1[2])
      } else {
        s <- ( point.xy[1]-p1[1])/(p2[1]-p1[1])
      }
      smudge <-  (.Machine$double.eps ^ 0.5)
      if (s>=0-smudge && s<= 1+smudge) {
        ison <- TRUE;
        break;
      }
    }
  }
  if (ison) { return(nix) } else { return(NA) }
}
#'@export
setMethod(".checkPointOnEdge",c("VDedgeLines"),function(edge,point.xy) {
  return(!is.na(.find.point.on.EdgeLines(edge,point.xy)))
}
)

#'@export
.face.midplace <- function(drawing,faceName) {
  # try forming the centroid of the points at the midplace of each edge
  #	browser()
  #	edgeClasses <- .faceEdgeClasses(drawing,faceName)
  #	stopifnot( (length(edgeClasses)==2 & all(edgeClasses=="VDedgeSector")))
  edges <- .face.to.faceEdges(drawing,faceName)
  midpoints <- t(sapply(edges,.midpoint))
  midpoints.centroid <- matrix(apply(midpoints,2,mean),ncol=2,byrow=TRUE)
  midpoints.centroid
}

#'@export
setMethod(".splitEdgeAtPoint",c("VDedgeSector"),function(edge,point.xy) {
  new1 <- edge
  new2 <- edge
  pointName <- rownames(point.xy)
  new1@to <- pointName
  new2@from <- pointName
  pointTheta <- .point.xy.to.theta(point.xy,edge@centre)
  #print(edge)
  #print(pointTheta)
  if (edge@toTheta > 0) {
    stopifnot(edge@fromTheta>= pointTheta & pointTheta <= edge@fromTheta)
    new1@toTheta <- pointTheta
    new2@fromTheta <- pointTheta
  } else {
    if (pointTheta> edge@fromTheta) {
      new1@toTheta <- pointTheta - 2*pi
      new2@fromTheta <- pointTheta
      new2@toTheta <- edge@toTheta+ 2*pi
    } else {
      new1@toTheta <- pointTheta
      new2@fromTheta <- pointTheta
    }
  }
  new2@fromTheta <- pointTheta
  #print(new1)
  #print(new2)
  new1 <- .normalise.sector(new1)
  new2 <- .normalise.sector(new2)
  list(new1,new2)
})

#'@export
setMethod(".splitEdgeAtPoint",c("VDedgeLines"),function(edge,point.xy) {
  nix <- .find.point.on.EdgeLines(edge,point.xy)
  if (is.na(nix)){ stop(sprintf("%s is not in edge",rownames(point.xy))) }
  new1 <- edge
  new2 <- edge
  pointName <- rownames(point.xy)
  new1@to <- pointName
  new2@from <- pointName

  new1@xy <- rbind(new1@xy[1:nix,],as.numeric(point.xy))
  n2rest <- new2@xy[(nix+1):nrow(new2@xy),,drop=FALSE]
  #show(n2rest)
  if (all(fequal(as.numeric(point.xy),n2rest[1,]))) {
    new2@xy <- n2rest
  } else {
    new2@xy <- rbind(as.numeric(point.xy),new2@xy[(nix+1):nrow(new2@xy),])
  }
  #show(edge)
  #show(pointName)
  #show(new1@xy)
  #show(new2@xy)
  list(new1,new2)
})

#'@export
spliceinstead <- function(vec,old,new) {
  medge <- match(old,vec)
  if (all(is.na(medge))) {
    return(vec)
  }
  upto <- if (medge[1]>1) { vec[1:(medge[1]-1)]} else { character(0) }
  endm <- medge[length(medge)]
  after <- if (endm  < length(vec)) { vec[(endm +1):length(vec)] } else { character(0) }
  c(upto,new,after)
}



#'@export
setMethod(".midpoint",c("VDedgeLines"),function(edge){
  edgexy <- .edge.to.xy(edge)
  if (nrow(edgexy)%%2 == 1) {
    midn <- (nrow(edgexy)+1)/2
    midn <- c(midn,midn)
  }	else {
    midn <- nrow(edgexy)/2
    midn <- c(midn,midn+1)
  }
  midx <- edgexy[midn,]
  midmean <- matrix(apply(midx,2,mean),ncol=2)
  midmean
})
#'@export
setMethod(".midpoint",c("VDedgeSector"),function(edge){
  theta <- (edge@fromTheta+edge@toTheta)/2
  point.xy <- .theta.to.point.xy(theta,r=edge@radius,centre=edge@centre)
  point.xy
})

#'@export
setClass("TDEdgeList",representation(edgeList="list"))
#'@export
setClass("TDFaceList",representation(faceList="list",faceSignature="list")) # of the same length; the name of the face is its name in the list
#'@export
.faceNames <- function(drawing,onlyVisible=FALSE) {
  faceNames <- names(drawing@faceList )
  if (onlyVisible) {
    faceNames <- setdiff(faceNames,"DarkMatter")
  }
  faceNames
}
#'@export
.faceSignatures <- function(drawing,onlyVisible=FALSE) {
  faceSignatures <- drawing@faceSignature
  if (onlyVisible) {
    faceSignatures[["DarkMatter"]] <- NULL
  }
  faceSignatures
}

#'@export
updateSignature <- function(drawing,faceNames,suffix) {
  for (faceName in faceNames) {
    sig <- drawing@faceSignature[[faceName]]
    if (sig=="DarkMatter" & suffix =="1") {
      sig <-  paste(c(rep("0",length(drawing@setList)-1),"1"),collapse="")
    } else {
      sig <- paste(sig,suffix,sep="")
    }
    drawing@faceSignature[[faceName]] <- sig
  }
  drawing
}
#'@export
setSignature <- function(drawing,faceName,signature) {
  drawing@faceSignature[[faceName]] <- signature
  drawing
}


#'@export
.faceEdgeNames <- function(drawing,faceName,unsigned=FALSE,type="face") {
  if (type=="set") {
    edges <- drawing@setList[[faceName]]
  } else {
    edges <- drawing@faceList[[faceName]]
  }
  if (unsigned) { edges <- sub("^-","",edges);  }

  edges
}
#'@export
.faceEdgeClasses <- function(drawing,faceName,type="face") {
  if (type=="set") {
    edges <- drawing@setList[[faceName]]
  } else {
    edges <- drawing@faceList[[faceName]]
  }
  unsigned.edges <- sub("^-","",edges);
  res <- sapply(drawing@edgeList[unsigned.edges],function(x)as.character(class(x)))
  res
}

#'@export
renameFaces <- function(drawing,oldName,newName) {
  stopifnot(length(oldName) == length(newName))
  oldFaceNames <- names(drawing@faceList)
  names(oldFaceNames) <- oldFaceNames
  newFaceNames <- oldFaceNames
  newFaceNames[oldName] <- newName
  newix <- which(duplicated(newFaceNames))
  for (ix in seq_along(newix)) {
    six <- 1;
    while(TRUE) {
      newName <- paste(newFaceNames[newix[ix]],six,sep="-")
      if (! newName %in% newFaceNames) {
        break
      }
      six <- six + 1
    }
    newFaceNames[newix[ix]] <- newName
  }

  for (i in seq_along(oldName)) {
    names(drawing@faceList) <- newFaceNames
    names(drawing@faceSignature) <- newFaceNames[oldFaceNames]
  }
  drawing
}

#'@export
setMethod("show","TDFaceList",function(object){
  facedf <- do.call(rbind,lapply(object@faceList,function(face){
    data.frame(faces=paste(face,collapse=";"))}))
  print(facedf)
  sdf <- data.frame(sig=do.call(c, object@faceSignature))
  print(sdf)
})

#'@export
spliceEdgeIntoFace <- function(drawing,faceName,edgeName,edgeNames,doReverse=TRUE) {
  revEdgeName <- sub("^--","",paste("-",edgeName,sep=""))
  revEdgeNames <- rev(sub("^--","",paste("-",edgeNames,sep="")))
  thisFaceList <- drawing@faceList[[faceName]]
  thisFaceList  <- spliceinstead(thisFaceList  ,edgeName,edgeNames)
  if (doReverse) {
    thisFaceList  <- spliceinstead(thisFaceList  ,revEdgeName,revEdgeNames)
  }
  drawing@faceList[[faceName]] <- thisFaceList
  drawing@recentChanges <- edgeNames
  drawing
}

#'@export
.startFaceAtPoint <- function(drawing,faceName,from) {
  FacePoints <-  .points.of.face (drawing,faceName)
  fromix=match(from,FacePoints)
  if (is.na(fromix)) { stop(sprintf("%s is not a point in face %s",from,faceName)) }
  oldFace <- drawing@faceList[[faceName]]
  face <- c(oldFace[(fromix):length(oldFace)],oldFace[seq(length=fromix-1)])
  drawing@faceList[[faceName]] <- face
  drawing
}


#'@export
addFace <- function(drawing,faceName,faceSignature,face,edit=FALSE) {
  #cat(sprintf("Adding face %s\n",faceName))
  newfaceName <- faceName
  if (!edit & !faceName=="DarkMatter") { # a new face.. but we won't overwrite an existing one with the same name unless it is dark matter
    if (faceName %in% .faceNames(drawing)) {
      ix <- 1;
      while(TRUE) {
        newfaceName <- paste(faceName,ix,sep="-")
        if (!newfaceName %in% .faceNames(drawing)) { break }
        ix <- ix+1
      }
      #cat(sprintf("...changed to  %s\n",newfaceName))
    }
  }
  #if (newfaceName %in% .faceNames(drawing)) { cat(sprintf("Adding %s which already exists with edit %s\n",newfaceName,edit)) }
  drawing@faceList[[newfaceName ]] <- face
  drawing@faceSignature[[newfaceName ]] <- faceSignature
  list(drawing=drawing,faceName=newfaceName)
}
#'@export
deleteFace <- function(drawing,faceName) {
  drawing@faceList[[faceName]] <- NULL
  drawing@faceSignature[[faceName]] <- NULL
  drawing
}
#'@export
getFace <- function(drawing,faceName,reverse=FALSE) {
  res <-drawing@faceList[[faceName]]
  if (reverse) {
    res <- rev(	sub("^--","",paste("-",res,sep="")))
  }
  res

}


#'@export
setClass("TissueDrawing",representation(
  "TDEdgeList", # named list of VDedgeDrawns
  "TDFaceList", # named list of (edge,hand) pairs
  setList="list", # named list of (edge, hand) pairs
  nodeList="list", # named list of xy coordinates
  recentChanges="character" # used in gross point injection code
)
)


# nb dont currently require that all edges in edge list are actually used in faceList
#'@export
.validateFaces <- function(drawing) {
  cat(sprintf("Validating a drawing on %d sets...",length(drawing@setList)))

  for (faceName in .faceNames(drawing)) {
    # check we have all the edges
    for (edge.name in .faceEdgeNames(drawing,faceName)) {
      if (! .edge.in.Drawing(drawing,edge.name)) {
        stop(sprintf("Face %s has unknown edge %s",faceName,edge.name))
      }
    }
    # then that points are visited in sequence
    thisFaceEdges<- .face.to.faceEdges(drawing,faceName)
    fromtomat <- sapply(thisFaceEdges,function(y){c(y@from,y@to)})
    for (ix in seq_len(ncol(fromtomat))) {
      if (ix==ncol(fromtomat)){jx<-1}else{jx<-ix+1}
      if (!(fromtomat[2,ix]==fromtomat[1,jx])	) {
        print(fromtomat)
        stop(sprintf("Face %s is wrong",faceName))
      }
    }

  }
  cat(sprintf("...done\n"))
}
#'@export
.validateDrawing <- function(drawing) {
  .validateFaces(drawing)
  for (set.name in names(drawing@setList )) {
    for (edge.name in drawing@setList [[set.name]]) {
      if (! .edge.in.Drawing(drawing,edge.name)) {
        stop(sprintf("Set %s has unknown edge %s",set.name,edge.name))
      }
    }
  }
  for (edge.name in names(drawing@edgeList)) {
    edge = drawing@edgeList[[edge.name]]
    if ( !(edge@from %in% names(drawing@nodeList))) {
      stop(sprintf("Edge %s has unknown from node %s",edge.name,edge@from))
    }
    if ( !(edge@to %in% names(drawing@nodeList))) {
      stop(sprintf("Edge %s has unknown to node %s",edge.name,edge@to))
    }
  }
  faceSignatures <- unlist(.faceSignatures(drawing))
  if (faceSignatures[names(faceSignatures)=="DarkMatter"] != "DarkMatter") {
    warning(sprintf("Dark matter face has sig %s\n"),faceSignatures[names(faceSignatures)=="DarkMatter"])
  }
  nsig <- faceSignatures[!faceSignatures=="DarkMatter"]
  issig <- sapply(nsig,function(s){regexpr("^[01]*$",s)>0})
  if (!all(issig)) {
    warning(sprintf("Faces %s have sigs %s\n",paste(names(nsig)[!issig],collapse=";"),paste((nsig)[!issig],collapse=";")))
  }
  siglen <- sapply(nsig,nchar)
  if (length(unique(siglen))>1) {
    warning(sprintf("sigs %s differ in length\n",paste(nsig,collapse=";")))
  }
  siglen <- unique(siglen)[1]
  if (any(duplicated(nsig))) {
    dupsig <- unique(nsig[duplicated(nsig)])
    sapply(dupsig,function(sig){
      cat(sprintf("sig %s duplicated in faces %s\n",sig,paste(names(nsig)[nsig==sig],collapse=";")))
    })
  }
  Indicator <- ifelse((data.matrix(do.call(expand.grid,lapply(seq(1,length=unique(siglen)),function(x){c(0,1)}))))==1,1,0)
  inn <- apply(Indicator ,1,paste,collapse="")
  inn[inn==paste(rep("0",siglen),collapse="")] <- "DarkMatter"
  signotindiag <- faceSignatures[!faceSignatures %in% inn ]
  if (length(signotindiag )>0) {
    warning(sprintf("Signatures %s not present in diagram",paste(signotindiag ,collapse=";")))
  }
}

#'@export
setMethod("show","TissueDrawing",function(object){
  edgedf <- do.call(rbind,lapply(object@edgeList,
                                 function(edge) {
                                   df <- data.frame(from=edge@from,to=edge@to,type=as.character(class(edge)))

                                   if (inherits(edge,"VDedgeSector")) {
                                     df <- cbind(df,data.frame(npoints=NA,centre=paste(edge@centre,collapse=","),hand=edge@hand))
                                   } else {
                                     df <- cbind(df,data.frame(npoints=nrow(edge@xy),centre=NA,hand=NA))
                                   }
                                 }
  ))
  print(edgedf)
  nodedf <- do.call(rbind,lapply(object@nodeList,function(node){
    dimnames(node)<- NULL; df <- data.frame(node); }))
  print(nodedf)
  show(as(object,"TDFaceList"))
  setdf <- do.call(rbind,lapply(object@setList,function(face){
    data.frame(paste(face,collapse=";"))}))
  print(setdf)

})


#'@export
.VDPlotArcs <- function(drawing,arcnames,arrowfunc=NULL,gp=gpar()) {
  drawing<-  as(drawing,"TissueDrawing")
  edgeList <- drawing@edgeList
  if (missing(arcnames)) {
    arcnames <- names(edgeList)
  }
  for (arcname in arcnames) {
    if (arcname %in% names(edgeList))
      arcxy <- .edge.to.xy(edgeList[[arcname]])
    else {
      revEdge <- sub("^--","",paste("-",arcname,sep=""))
      if (revEdge %in% names(edgeList) ) {
        arcxy <- .edge.to.xy(.reverseEdge(edgeList[[revEdge ]]))
      } else {
        stop(sprintf("Can't find edge %s in drawing\n",arcname))
      }
    }
    grid.lines(arcxy[,1],arcxy[,2],default.units="native",arrow=arrowfunc,gp=gp)
  }
}


#'@export
.PlotSetBoundaries.TissueDrawing <- function(drawing,gp){
  #browser()
  drawing <- as(drawing,"TissueDrawing")
  setList <- drawing@setList
  setNames <- names(drawing@setList)
  if (missing(gp)) {
    gp <- SetColours(drawing)
  }
  for (setName in setNames) {
    .VDPlotArcs(drawing,setList[[setName]],gp=gp[[setName]])
  }
}
#'@export
setMethod("PlotSetBoundaries","TissueDrawing",.PlotSetBoundaries.TissueDrawing)

#'@export
setMethod("PlotNodes","TissueDrawing",function(drawing,gp){
  dv <- as(drawing,"TissueDrawing")
  pxy <- dv@nodeList
  xy <- do.call(rbind,pxy)
  grid.text(x=xy[,1],y=xy[,2],label=names(pxy),default.units="native",
            just=c("left","bottom"))
})
#'@export
.face.to.faceEdges <-  function(drawing,faceName,type="face") {
  if (type=="set") {
    faceEdgeNames <- drawing@setList[[faceName]]
  } else {
    faceEdgeNames <- .faceEdgeNames(drawing,faceName)
  }
  faceSign <- substring(faceEdgeNames,1,1)=="-"
  unsignedEdgeNames <- sub("^-","",faceEdgeNames)
  notinedgeList <- unsignedEdgeNames [! unsignedEdgeNames %in% names(drawing@edgeList)]
  #if (length(notinedgeList)>0) {
  #  stop(sprintf("Face %s has unknown edges %s",faceName,paste(notinedgeList, collapse=" ")))
  #}
  faceEdges <- drawing@edgeList[unsignedEdgeNames ]
  names(faceEdges) <- faceEdgeNames
  faceEdges[faceSign] <- lapply(faceEdges[faceSign],.reverseEdge)
  faceEdges
}
#'@export
.face.toxy <- function(drawing,faceName,dx=0.05,type="face") {
  faceEdges <- .face.to.faceEdges(drawing,faceName,type=type)
  face.Sxy <- lapply(faceEdges,function(x).edge.to.xy(x,dx=dx))
  face.Sxy <- lapply(face.Sxy,function(x)x[-nrow(x),,drop=FALSE])

  all.xy <- do.call(rbind,face.Sxy)
  all.xy
}

#'@export
.face.area <- function(drawing,faceName) {
  all.xy <- .face.toxy(drawing,faceName);
  .polygon.area(all.xy)
}
#'@export
.polygon.area <- function(xy) {
  # this area is negative for clockwise polygons, sigh
  xy1 <- xy; xy2 <- xy[ c(2:nrow(xy),1),]
  x1 <- xy1[,1];y1 <-xy1[,2];x2<-xy2[,1];y2<- xy2[,2]
  det <- x1*y2 - x2*y1
  (sum(det)/2)

}
#'@export
faceAreas <- function(drawing) {
  sapply(.faceNames(drawing),function(faceName)abs(.face.area(drawing,faceName)))
}
#'@export
.polygon.centroid <- function(all.xy) {
  xy1 <- all.xy; xy2 <- all.xy[ c(2:nrow(all.xy),1),]
  x1 <- xy1[,1];y1 <-xy1[,2];x2<-xy2[,1];y2<- xy2[,2]
  area <- .polygon.area(all.xy)
  if (area>0) {
    cx <- sum((x1+x2) * ( x1 * y2 - x2 * y1))/(6* area)
    cy <- sum((y1+y2) * ( x1 * y2 - x2 * y1))/(6* area)
  } else {
    cx <- mean(x1);cy <- mean(y1)
  }
  centroid.xy <- matrix(c(cx,cy),ncol=2)
  centroid.xy
}
#'@export
.face.centroid <- function(drawing,faceName) {
  all.xy <- .face.toxy(drawing,faceName)
  res <- .polygon.centroid(all.xy)
  names(res) <- "centroid"
  res
}
#'@export
.PlotFace.TissueDrawing <- function(drawing,faceName,dx=0.05,gp=gpar(),doDarkMatter=FALSE) {
  #cat(faceName,"\n")
  if (!doDarkMatter & faceName=="DarkMatter") {
    return()
  }
  all.xy <- .face.toxy(drawing,faceName,dx=dx)
  #  first we do the fill using the gps
  if (!is.null(all.xy)) {
    grid.polygon(all.xy[,1],all.xy[,2],default.units="native",gp=gp)
  }
  if (!is.null(gp$lty)) { # have a line spec for the outside which we no longer index by set number
    faceEdges <- .face.to.faceEdges(drawing,faceName)
    face.Sxy <- lapply(faceEdges,.edge.to.xy,dx=dx)

    lapply(1:length(face.Sxy),function(edgeix) {
      faceEdge <-  faceEdges[[edgeix]]
      face.xy <- .edge.to.xy(faceEdge)
      if (nrow(face.xy)>0) {
        grid.lines(face.xy[,1],face.xy[,2],
                   default.units="native",gp=gp)
      }
    })
  }
}
#'@export
.PlotFaceNames.TissueDrawing <- function(drawing,faceNames,signature=TRUE){
  if(missing(faceNames)) {
    faceNames <- .faceNames(drawing,onlyVisible=TRUE)
  }
  if (signature) {
    faceSignatures <- .faceSignatures(drawing,onlyVisible=TRUE)
    label <- (faceSignatures[faceNames])
  } else {
    label <- faceNames
  }
  for (faceName in faceNames) {
    text.xy <- .find.point.within.face (drawing,faceName)
    #		grid.points(x=text.xy[,1],y=text.xy[,2],default.units="native")
    grid.text(x=text.xy[,1],y=text.xy[,2],label=label[[faceName]],default.units="native")
  }
}

#'@export
.PlotFaces.TissueDrawing<- function(drawing,faceNames,gp,arrow,colourAlgorithm){
  if(missing(faceNames)) {
    faceNames <- .faceNames(drawing)
  }
  if (missing(gp)){
    gp <- FaceColours(drawing=drawing,faceNames=faceNames,colourAlgorithm=colourAlgorithm)
  }
  for (face.ix in seq_along(faceNames)) {
    faceName <- faceNames[face.ix]
    .PlotFace.TissueDrawing(drawing,faceName,gp=gp[[faceName]])
  }
}
#'@export
setMethod("PlotFaces","TissueDrawing",.PlotFaces.TissueDrawing)
#'@export
.find.point.on.face <- function(drawing,faceName) {
  edgeName <- .faceEdgeNames(drawing,faceName)[1]
  edgeName <- sub("^-","",edgeName)
  edge <- drawing@edgeList[[edgeName]]
  point <- .midpoint(edge)
  point
}
#'@export
.face.maxradius <- function(drawing,faceName) {
  edgebb <- lapply(.face.to.faceEdges(drawing,faceName),function(x)x@bb)
  absbb <- max(sapply(edgebb,function(x)max(abs(x))))
  maxradius <- sqrt(2)*absbb
  maxradius
}

#'@export
.find.point.within.face <- function(drawing,faceName,treat.dark.matter.as.face=FALSE) {
  if (faceName=="DarkMatter" & treat.dark.matter.as.face) {
    faceName <- ".fpwf"
    drawing <- renameFaces(drawing,"DarkMatter",faceName)
    # has the effect of treating as an ordinary face
  }
  edgeClasses <- .faceEdgeClasses(drawing,faceName)
  if (all(edgeClasses=="VDedgeSector") & length(edgeClasses)==2) {
    aPoint <- 	.face.midplace(drawing,faceName)
    if (.is.point.within.face(drawing,faceName,aPoint )) {
      return(aPoint )
    } else {
      aPoint <- .face.centroid(drawing,faceName=faceName)
      if (.is.point.within.face(drawing,faceName,aPoint )) {
        return(aPoint )
      }
    }
  } else { #otherwise test in other order
    aPoint <- 	.face.centroid(drawing,faceName=faceName)
    if (.is.point.within.face(drawing,faceName,aPoint )) {
      return(aPoint )
    } else {
      aPoint <- .face.midplace(drawing,faceName=faceName);
      if (.is.point.within.face(drawing,faceName,aPoint )) {
        return(aPoint )
      }
    }
  }

  ear.triangle <- .find.triangle.within.face(drawing,faceName)
  earCentroid <- .polygon.centroid(ear.triangle)
  if (!	.is.point.within.face(drawing,faceName,earCentroid )) {
    stop(sprintf("Ear method failed in face %s\n",faceName))
  }
  return(earCentroid)
}
#'@export
.find.triangle.within.face <- function(drawing,faceName) {
  xy <- .face.toxy(drawing,faceName)
  A <- .face.area(drawing,faceName)
  if (A==0) { # collinear
    return(xy[1:3,])
  }
  xy <- rbind(xy,xy[1:2,])
  fix <- NA
  for (ix in 2:(nrow(xy)-1)) {
    from <- xy[ix-1,,drop=FALSE]
    to <- xy[ix+1,,drop=FALSE]
    pt <- xy[ix,,drop=FALSE]
    thetafrom <- atan2( from[,2]-pt[,2],from[,1]-pt[,1])
    thetato <-   atan2(   to[,2]-pt[,2],to[,1]-pt[,1])
    thetato <- thetato - thetafrom
    thetato <- thetato %% (2 * pi)
    if (thetato > pi) { # not a convex point
      next
    }
    npoints <- .probe.chord.intersections(drawing,faceName,from,to)
    fromdist <- ((npoints[,1]-from[1])^2+(npoints[,2]-from[2])^2 ) * sign(npoints[,1]-from[1])
    npoints <- npoints[order(fromdist),]; fromdist <- sort(fromdist)
    fromix <- min(which(fequal(fromdist,0)))
    if (fromix !=1) {
      fromdist <- -fromdist
      npoints <- npoints[order(fromdist),];fromdist <- sort(fromdist)
      fromix <- min(which(fequal(fromdist,0)))
      stopifnot(fromix==1)
    }
    # the next point along has to be the to point otherwise intersection
    nextix <- min(which(!fequal(fromdist,0)))
    nextpt <- npoints[nextix,,drop=FALSE]
    nointersect <- all(fequal(nextpt,to))
    if (nointersect) {
      fix <- ix
      break
    }
  }
  if (is.na(fix)) {
    stop(sprintf("Can't find ears for face %s\n",faceName))
  }
  return(xy[ (fix-1):(fix+1),])
}

#'@export
internalPointsofFaces <- function(drawing) {
  fNames <-setdiff(.faceNames(drawing),"DarkMatter")
  res <- lapply(fNames ,function(x).find.point.within.face(drawing=drawing,x))
  res <- do.call(rbind,res)
  res <- rbind(res,c(NA,NA))
  rownames(res) <- c(fNames,"DarkMatter")

  res
}

#'@export
.edge.in.Drawing <- function(drawing,edge.name) {
  unsignedEdgeName <- sub("^-","",edge.name)
  unsignedEdgeName %in% names(drawing@edgeList)
}

#'@export
injectPoint <- function(drawing,edgeName,newPoint) {
  #print(edgeName);

  pointName <- rownames(newPoint)
  if (pointName %in% names(drawing@nodeList)) {
    existingPoint <- drawing@nodeList[[pointName]]
    if (!all(fequal(newPoint-existingPoint,0))) {
      stop(sprintf("Point %s already exists at a different place",pointName))
    }
  } else {
    drawing@nodeList[[pointName]] <- newPoint
  }

  if (is.null(edgeName)) {
    # just an isolated point
    return()
  }

  thisEdge <- drawing@edgeList[[edgeName]]
  if (is.null(thisEdge)) {stop(sprintf("Edge %s not found",edgeName))	}
  if (!.checkPointOnEdge(edge=thisEdge,point.xy=newPoint)) {
    show(drawing)
    stop(sprintf("Point %s not on edge %s",pointName,edgeName))
  }

  new12 <- .splitEdgeAtPoint(thisEdge,newPoint)
  splitName <- strsplit(edgeName,split="|",fixed=TRUE)[[1]]
  if (length(splitName>= 3)) { setName <- splitName[3] } else {setName <- "?"}

  edgeNames <- c(paste(thisEdge@from,pointName,setName ,sep="|"),paste(pointName,thisEdge@to,setName ,sep="|"))
  drawing@edgeList[[edgeName]] <- NULL
  drawing@edgeList[[edgeNames[1]]] <- new12[[1]]
  drawing@edgeList[[edgeNames[2]]] <- new12[[2]]

  # now insert into the setlist

  for (setName in names(drawing@setList)) {
    if (edgeName %in% drawing@setList[[setName]]) {
      drawing@setList[[setName]] <- spliceinstead(drawing@setList[[setName]],edgeName,edgeNames)
    }
  }

  # and now into the facelist
  for (faceName in .faceNames(drawing)) {
    drawing <- spliceEdgeIntoFace(drawing,faceName,edgeName,edgeNames)
  }

  drawing
}

#'@export
pnpoly <- function(xp,yp,x,y) {
  npol <- length(xp); stopifnot(npol==length(yp))
  c= 0
  for (i in seq_len(npol)) {
    if (i==1) { j<- npol } else {j<-i-1}
    # cat(i," ",j,"\n")
    if ((((yp[i]<=y) && (y<yp[j])) ||
         ((yp[j]<=y) && (y<yp[i]))) &&
        (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i])) {
      c <- c+1
    }
  }
  return ( c %%2 == 1)
}


#'@export
pnpolytest <- function() {
  pnpoly( xp=c(-1,1,1,-1),yp=c(-1,-1,1,1),x=0,y=0)
  pnpoly( xp=c(-1,1,1,1,-1),yp=c(-1,-1,0,1,1),x=0,y=0)
  pnpoly( xp=c(-1,1,1,1,1,-1),yp=c(-1,-1,0,0,1,1),x=0,y=0)
  pnpoly( xp=c(1,1,1,-1,-1,1),yp=c(0,0,1,1,-1,-1),x=0,y=0)
  pnpoly( xp=c(1,1,-1,-1,1,1),yp=c(0,1,1,-1,-1,0),x=0,y=0)
  pnpoly( xp=c(-3,-2,-3,-3),yp=c(2,1,0,2),x=-4.5,y=0)
  pnpoly( xp=c(-3,-2,-3),yp=c(2,1,0),x=-4.5,y=0)
}

#'@export
.is.point.within.face <- function(drawing,faceName,point.xy,type="face") {
  .face.xy <-  .face.toxy(drawing,faceName,type=type)
  inFace <- pnpoly(.face.xy[,1],.face.xy[,2],point.xy[,1],point.xy[,2])
  if (faceName=="DarkMatter") {
    inFace <- !inFace
  }
  return(inFace)
}
#'@export
.is.face.within.set <- function(drawing,faceName,setName) {
  aPoint <- .find.point.within.face(drawing,faceName)
  .is.point.within.face(drawing,faceName=setName,point.xy=aPoint,type="set")

}

#'@export
.points.of.face <- function(drawing,faceName,from) {
  # these are returned in sequence, starting from (the first) FROM if specified
  thisFaceEdges<- .face.to.faceEdges(drawing,faceName)
  fromtomat <- sapply(thisFaceEdges,function(y){c(y@from,y@to)})
  thisFacePoints <- as.vector(c(fromtomat[1,1],fromtomat[2,-ncol(fromtomat)]))
  if (!missing(from)) {
    thisFacePoints2 = c(thisFacePoints,thisFacePoints)
    mix = match(from,thisFacePoints2)
    if (is.na(mix)){stop(sprintf("%s is not in face %s",from,faceName))}
    thisFacePoints <- thisFacePoints2[ (mix): (mix+ length(thisFacePoints)-1)]
  }
  thisFacePoints
}
#'@export
.find.face.containing.edge <- function(drawing,edgeList) {
  # normally faces _dont_ contain edges but when we are injecting a new one
  # we want to find which face it is crossing

  # a new edge must be inside one of the faces which have from and to as members
  # or outside all of them (equivalently in the dark matter)
  from= edgeList[[1]]@from
  to = edgeList[[length(edgeList)]]@to
  pointsPerFace <- lapply(.faceNames(drawing),function(faceName){
    .points.of.face(drawing,faceName)
  })
  names(pointsPerFace) <- .faceNames(drawing)
  fromtoInFace <- sapply(pointsPerFace ,function(x)from %in% x & to %in% x)
  fromtoFaceNames <- names(fromtoInFace)[fromtoInFace]

  inFaceName <- "DarkMatter"
  edge.midpoint <- .midpoint(edgeList[[1]])
  for (faceName in setdiff(fromtoFaceNames,"DarkMatter")) {
    if (.is.point.within.face(drawing,faceName,edge.midpoint)) {
      inFaceName <- faceName
      break
    }
  }
  inFaceName
}
#'@export
injectEdge <- function(drawing,newEdgeList,inFaceName,set2Name,addToList=TRUE) {
  if(addToList) {	drawing@edgeList <- c(drawing@edgeList,newEdgeList) }

  inFaceName <- .find.face.containing.edge(drawing=drawing,edgeList=newEdgeList)
  edgeNames <- names(newEdgeList);
  edge.from <- newEdgeList[[1]]@from
  edge.to <- newEdgeList[[length(newEdgeList)]]@to
  #cat(inFaceName,"\n")
  drawing <- .startFaceAtPoint(drawing,faceName=inFaceName,from=edge.from)
  oldFacePoints <- .points.of.face (drawing,faceName=inFaceName)

  #
  fromix.possible = which(edge.from==oldFacePoints)
  toix.possible = which(edge.to==oldFacePoints)
  if (length(toix.possible)==0) { browser();stop(sprintf("%s is not in face %s",edge.to,inFaceName)) }


  if (length(fromix.possible)==1) {
    fromix <- fromix.possible
  } else  {
    warning(sprintf("Face %s has points %s; can't cope well with joining repeated FROM point %s yet",
                    inFaceName,paste(oldFacePoints,collapse=","),edge.from))
    fromix <- fromix.possible[1]
    # we know we want to split the face between FROM and TO, but
    # the trouble is that eg from may be repeated in the edge of the
    # face and we need to pick the right one
    # first find the right FROM ; take the last possible TO
  }

  if (length(toix.possible)==1) {
    toix<- toix.possible
  } else  {
    warning(sprintf("Face %s has points %s; can't cope well with joining repeated TO point %s yet",
                    inFaceName,paste(oldFacePoints,collapse=","),edge.to))
    toix<- toix.possible[length(toix.possible)]
  }

  inFaceSignature <- .faceSignatures(drawing)[[inFaceName]]
  nSets <- length(drawing@setList)
  if (inFaceName=="DarkMatter") {
    newFaceSigP <- paste(c(rep("0",nSets-1),"1"),collapse="")
    newFaceSigM <- "DarkMatter"
  } else {
    if (nchar(inFaceSignature)!=nSets) {
      newFaceSigP <- paste(inFaceSignature ,"1",sep="")
      newFaceSigM <- paste(inFaceSignature ,"0",sep="")
    } else {
      # that means this face has already been subdivided,
      # so further subdivision takes us back out of the Set
      newFaceSigP <- inFaceSignature
      newFaceSigM <- paste(substr(inFaceSignature ,1,nSets-1),"0",sep="")
      #		if (newFaceSigM==paste(rep("0",nSets),collapse="")) {
      #			newFaceSigM <- "DarkMatter"
      #		}
    }

  }
  newFaceNamep <- newFaceSigP; newFaceNamem <- newFaceSigM

  # we duplicate so we can wrap around
  oldFace <- .faceEdgeNames(drawing,inFaceName)
  oldFace2 <- c(oldFace,oldFace)
  reverseEdgeNames <- rev(sub("--","",paste("-",edgeNames,sep="")))


  # using the forward new edge will cut out FROM to TO and replace it by our new edgeNames
  # and then from the old face TO, back round the long way, to FROM
  # the only time that is wrong is if toix==fromix and  the new set completely encircles the old one
  if (toix==fromix) {
    new1 <- edgeNames
  }	else {
    f1start <- toix
    f1end <- fromix+length(oldFacePoints)
    new1 <- c(edgeNames,oldFace2[ f1start:(f1end-1)])
  }
  # that will be the new +ve entry
  res <- addFace(drawing,newFaceNamep,newFaceSigP,new1)
  drawing <- res$drawing; newFaceNamep <- res$faceName
  # the exception is when the new edge completely encircles the old one (and so fromix==toix as well)
  isEncircled <- FALSE
  if (fromix==toix) {
    oldPoint <- .find.point.on.face(drawing,inFaceName)
    oldinnew <- .is.point.within.face(drawing,faceName=newFaceNamep,point.xy=oldPoint)
    isEncircled <-  oldinnew
  }
  if (isEncircled) {
    newFace <- c(new1,oldFace)
    drawing <- addFace(drawing,newFaceNamep,newFaceSigP,newFace,edit=TRUE)$drawing
  }

  # using the reverse edge keeps FROM to TO, then returns with the new edge
  if(!isEncircled) {
    if (fromix==toix) {
      f2start <- fromix
      f2end <- fromix+length(oldFace)-1
    } else {
      f2start <- fromix
      f2end <- toix - 1
    }
    stopifnot(f2start*f2end!=0)
    new2 = c(oldFace2[ f2start:f2end],reverseEdgeNames)
  } else {
    new2 <- reverseEdgeNames
  }
  res <- addFace(drawing,newFaceNamem,newFaceSigM ,new2)
  drawing <- res$drawing; newFaceNamem <- res$faceName

  if (inFaceName != newFaceNamem & inFaceName != newFaceNamep) {
    drawing <- deleteFace(drawing,inFaceName)
  }


  #cat(sprintf("Split face %s into %s and %s\n",inFaceName,newFaceNamep ,newFaceNamem))
  drawing
}


#'@export
newTissueFromCircle <- function(centre.xy,radius,Set=1,nodes=1) {
  nodeangles <-   2 * pi -  ( 0:(nodes-1) * 2 * pi / (nodes))
  p1.xy <- radius * cbind(cos(nodeangles),sin(nodeangles))
  p1.xy <- rep(centre.xy,each=nrow(p1.xy))+p1.xy

  rownames(p1.xy) <- paste("c",Set,1:nrow(p1.xy),sep="")

  nodeName <- rownames(p1.xy)[1]
  lhcircle <- newEdgeSector(from=nodeName,to=nodeName,radius=radius,fromTheta=2*pi,toTheta=0,centre=centre.xy,hand=1)
  edgeName <- paste(nodeName,nodeName,Set,sep="|")
  edgeList <- list(lhcircle); names(edgeList) <- edgeName
  faceName <- "1"
  faceList <- list(edgeName,paste("-",edgeName,sep=""));names(faceList)<-c(faceName,"DarkMatter")
  faceSignature <- lapply(names(faceList),function(x){x}); names(faceSignature) <- names(faceList)
  nodeList <- list(p1.xy[1,,drop=FALSE])
  names(nodeList) <- rownames(p1.xy)[1]
  setList <- faceList[1]; names(setList) <- paste("Set",Set,sep="")
  VD <- new("TissueDrawing",edgeList=edgeList,faceList=faceList,faceSignature=faceSignature ,
            nodeList=nodeList,setList=setList)
  if  (nrow(p1.xy)>1) {
    VD <- injectPoints(VD,edgeName,p1.xy[-1,,drop=FALSE])
  }
  VD
}
#'@export
newTissueFromEllipse <- function(f1,phi,e,a,Set,dx=0.05) {
  arclength <- (4*pi)
  nintervals <- arclength/dx

  twoc <- a* e* 2
  f2 <- f1+  twoc*c(-cos(phi),sin(phi))
  theta <- seq(0,2*pi,length=nintervals)
  r <- (a * (1-e^2))/(1+e*cos(theta+phi))
  x <- f1[1]+r*cos(theta)
  y <- f1[2]+r*sin(theta)

  points.xy <- cbind(x,y)
  rownames(points.xy) <- paste("e",letters[Set],1:nrow(points.xy),sep="")
  newTissueFromPolygon(points.xy=points.xy,Set=Set)
}

#'@export
newTissueFromPolygon <- function(points.xy,Set=1) {
  points.xy <- 	.removeDuplicates (points.xy)
  if (nrow(points.xy)<3) {stop("Not enough distince points for a polygon")}
  isclockwise <- (.polygon.area(points.xy) < 0)
  if (!isclockwise) {
    points.xy <- points.xy[nrow(points.xy):1,]
  }

  frompoint <- points.xy[1,,drop=FALSE]
  if (!is.null(rownames(frompoint))) {
    from = rownames(frompoint) ;
  } else {
    from <- paste("p",letters[Set],"1",sep="")
  }
  to = from;
  points.xy <- rbind(points.xy,frompoint )
  ledge<- newEdgeLines(from=from,to=from,xy=points.xy)
  edgeName <- paste(from,to,Set,sep="|")
  edgeList <- list(ledge); names(edgeList) <- edgeName
  faceName <- "1";
  faceList <- list(edgeName,paste("-",edgeName,sep=""));names(faceList)<-c(faceName,"DarkMatter")
  nodeList <- list(frompoint); names(nodeList) <- from
  faceSignature <- lapply(names(faceList),function(x){x}); names(faceSignature) <- names(faceList)
  setList <- faceList[1]; names(setList) <- paste("Set",Set,sep="")
  VD <- new("TissueDrawing",edgeList=edgeList,faceList=faceList,faceSignature=faceSignature ,
            nodeList=nodeList,setList=setList)
  VD
}

#'@export
injectPoints <- function(drawing,edgeName,newPoints) {
  if (nrow(newPoints)<1) { return(drawing) }
  newPoint <- newPoints[1,,drop=FALSE]
  drawing <- injectPoint(drawing=drawing ,edgeName=edgeName,newPoint=newPoint)
  newEdges <- drawing@recentChanges
  otherPoints <- newPoints[-1,,drop=FALSE]
  if(nrow(otherPoints)>0) {

    arepointsOn2 <- sapply(seq_len(nrow(otherPoints)) ,function(pointix){
      .checkPointOnEdge(edge=drawing@edgeList[[newEdges[2]]],otherPoints[pointix,,drop=FALSE])})
    pointsOn2 <- otherPoints[arepointsOn2,,drop=FALSE]
    if (nrow(pointsOn2)>0) {
      drawing <- injectPoints(drawing,newEdges[2],pointsOn2 )
    }

    arepointsOn1 <- sapply(seq_len(nrow(otherPoints)) ,function(pointix){
      .checkPointOnEdge(edge=drawing@edgeList[[newEdges[1]]],otherPoints[pointix,,drop=FALSE])})
    pointsOn1 <- otherPoints[arepointsOn1,,drop=FALSE]
    if (nrow(pointsOn1)>0) {
      drawing <- injectPoints(drawing,newEdges[1],pointsOn1 )
    }
  }

  drawing

}

#'@export
addSetToDrawing <- function(drawing1,drawing2,set2Name,remove.points=FALSE) {


  # ensure no clash of face names
  face2Name <- .faceNames(drawing2,onlyVisible=TRUE)
  stopifnot(length(face2Name )==1 )

  tempface2Name <- ".aSTD.temp";
  drawing2 <- renameFaces(drawing2,face2Name,tempface2Name)

  # check for name clashes, and also for identical points with different names
  new2 <- .check.clashes(drawing1,drawing2)

  # calculate a list of all the intersections and add them in as points
  res <- .add.intersection.points(drawing1=drawing1,drawing2=new2)
  new1=res$new1;new2=res$new2;intersectionPoints=res$intersectionPoints

  # we may have two edges with different names but identical geometry, if so use the name from diagram1
  res <- .check.duplicate.edges(drawing1=new1,drawing2=new2)
  new1<- res$new1; new2 <- res$new2

  # edges only in diagram2 need to be added to diagram1
  posnames <- sub("^-","",names(new2@edgeList)); negnames <- paste("-",posnames,sep="")
  newEdges <- new2@edgeList[! (posnames %in% names(new1@edgeList) | negnames %in% names(new1@edgeList)) ]
  new1@edgeList <- c(new1@edgeList,newEdges)
  # for lookups below, need to do the same in diagram2 in case we relabelled an edge that a face relies on
  new2@edgeList <- c(new2@edgeList,new1@edgeList[!names(new1@edgeList) %in% names(new2@edgeList)])


  # that will have updated the single set in new2
  new1@setList <- c(new1@setList,new2@setList)

  newNodes <- setdiff(names(new2@nodeList),names(new1@nodeList))
  new1@nodeList <- c(new1@nodeList,new2@nodeList[newNodes])


  # now split boundary of face2 into its edges
  face2Points <- .points.of.face(new2,tempface2Name )
  # are any of them intersection points?
  face2IntersectionPoints <- intersect(face2Points,intersectionPoints)

  if (length(face2IntersectionPoints)==0) {
    if (length(newEdges)==0) {
      new1 <- .addSetWithExistingEdges(new1,drawing2,tempface2Name)
    } else {
      new1 <- .addNonintersectingFace(new1,drawing2,tempface2Name)
    }
    if (!inherits(new1,"TissueDrawing")) { return(NA) } # when we can't build an invisible edge joining the two faces
  } else {
    new1 <- .addIntersectingFace(new1,new2,tempface2Name,face2IntersectionPoints)
  }
  new1 <- .merge.faces.invisibly.split(new1)

  if (remove.points) {
    new1 <- remove.nonintersectionpoints(new1)
  }
  new1


}

#'@export
.addSetWithExistingEdges<- function(drawing1,drawing2,tempface2Name) {
  # the new Set is solely comprised of existing edges
  # so there are no new faces
  # all we need to do is update the signatures
  # probably an easier way to do this, by tracking which edges came from which sets...
  # but we just cycle through the faces and update through brute force


  for (faceName in setdiff(.faceNames(drawing1),"DarkMatter")) {
    aPoint <- .find.point.within.face(drawing1,faceName)
    inFace <- .is.point.within.face(drawing=drawing1,faceName=tempface2Name,point.xy=aPoint,type="set")
    inFaceSig <- if (inFace) { "1"} else {"0"}
    drawing1<- updateSignature(drawing1,faceName,inFaceSig )
  }
  drawing1
}
#'@export
.addNonintersectingFace <- function(drawing1,drawing2,tempface2Name) {
  # drawing2 contains a single face
  #must be inside one of the faces or outside them all
  #either way can add the new face unchanged to the faceList

  res <- addFace(drawing=drawing1,faceName=tempface2Name,faceSignature="dummy",face=getFace(drawing2,tempface2Name))
  new1 <- res$drawing; tempface2Name<- res$faceName

  # then find which face it is within, first so we can set the signature correctly
  aPoint <- .find.point.within.face(drawing2,tempface2Name)
  outerFaceName <- ""
  for (faceName in .faceNames(new1)) {
    if(.is.point.within.face(drawing=new1,faceName=faceName,point.xy=aPoint)) {
      outerFaceName <- faceName
      break
    }
  }
  new1 <- setSignature(new1,tempface2Name,.faceSignatures(new1)[[outerFaceName]])

  # but then need to add invisible edges to join in to rest of drawing
  res <- .create.edge.joining.faces(drawing=new1,outerFaceName=outerFaceName ,innerFaceName=tempface2Name )
  if (!res$ok) {
    return(NA)
  }
  iedgeName <- res$edgeName; new1 <- res$drawing;
  redgeName <- paste("-",iedgeName,sep="")

  # point to attach to (called outer because I imagined the face being inside,
  # but also works when inserting a new face into dark matter and this point
  outerPoint <-  new1@edgeList[[iedgeName ]]@from
  innerPoint <- new1@edgeList[[iedgeName ]]@to
  new1 <- .startFaceAtPoint(new1,tempface2Name,innerPoint)
  newEdges <- c(iedgeName,getFace(new1,tempface2Name,reverse=TRUE),redgeName)
  # find the edge going in to it
  outerEdges <- .face.to.faceEdges(new1,outerFaceName)
  edgetoPoint <- names(outerEdges)[min(which(sapply(outerEdges,function(edge)edge@to==outerPoint)))]
  # normally when replacing edges we want to do it for both faces containing the edge,
  #  but not in this case hence doReverse=FALSE
  new1 <- spliceEdgeIntoFace (drawing=new1,faceName=outerFaceName,edgeName=edgetoPoint,edgeNames=c(edgetoPoint,newEdges),doReverse=TRUE)
  # now calculate the names
  oldFaceNames <- .faceNames(new1); faceNames <- oldFaceNames
  notInvolved <-  !faceNames %in% c(tempface2Name,"DarkMatter")
  faceNames[ notInvolved ] <- paste(faceNames[ notInvolved ],"0",sep="")
  if (outerFaceName=="DarkMatter") {
    face2Name <- paste(c(rep("0",length(new1@setList)-1),"1"),collapse="")
  } else {
    face2Name <- paste(outerFaceName,"1",sep="")
  }
  faceNames[ faceNames ==tempface2Name] <- face2Name
  new1 <- renameFaces(new1,oldFaceNames,faceNames)
  new1 <- updateSignature(new1,faceNames[notInvolved],"0")
  new1 <- updateSignature(new1,face2Name,"1")
  new1
}
#'@export
.find.point.in.diagram <- function(drawing,aPoint) {
  xy <- do.call(rbind,drawing@nodeList)
  dist <- (xy[,1]-aPoint[1])^2 + (xy[,2]-aPoint[2])^2
  isEqual <- fequal(dist,0)
  if (!any(isEqual)) { return(NA)}
  if (length(which(isEqual))>1) stop("A third nonuique point")
  pointName <- rownames(xy)[isEqual]
  return(pointName)
}
#'@export
.create.edge.joining.faces <- function(drawing,outerFaceName,innerFaceName) {
  # if outerFaceName is DarkMatter, then we really want to connect any
  # one of the other faces to innerFaceName, and the idea is to draw a line joining the centres of the two faces
  # that must have at least one segment which joins (something connected to the first face) to (something connected to) the second face
  # if outerFaceName is a regular face, (and then the innerFace is actually nested inside it, hence the names
  # then a point on its boundary will do as well
  # in practice the second face is always a single set though

  if (outerFaceName=="DarkMatter") {
    outerFaceForPoint <- setdiff(.faceNames(drawing),"DarkMatter")[1]
    outerPoint <- .find.point.within.face(drawing,outerFaceForPoint )
  } else {
    outerFaceForPoint <- outerFaceName
    outerPointName <- .points.of.face(drawing,outerFaceName)
    outerPoint <- drawing@nodeList[[outerPointName]]
  }
  innerPoint <- .find.point.within.face(drawing,innerFaceName)
  rownames(outerPoint) <- ".cejf"

  # find all the places it hits the 'inner' ie single set face
  innerpoints <- .probe.chord.intersections(drawing,innerFaceName,outerPoint ,innerPoint )
  innerpoints <- innerpoints [rownames(innerpoints ) != ".cejf",,drop=FALSE]
  # and all the points it hits things connected to the outer face, so have to look through all the other faces too
  outerpoints <- matrix(nrow=0,ncol=2)
  for (faceName in setdiff(.faceNames(drawing),c("DarkMatter",innerFaceName))) {
    opoints <- 	.probe.chord.intersections(drawing,faceName ,outerPoint ,innerPoint )
    outerpoints <- rbind(outerpoints,opoints )
    outerpoints <- unique(outerpoints [rownames(outerpoints ) != ".cejf",,drop=FALSE])
  }
  # code the points by 1 or 2 depending on whether they are on the inner or outer faces
  linepoints <- rbind(cbind(outerpoints,1),cbind(innerpoints,2))
  dist <- (linepoints[,1]-outerPoint [1])^2+(linepoints[,2]-outerPoint [2])^2
  # sort by distance from the outer set
  linepoints <- linepoints[order(dist),,drop=FALSE]
  lastOuter <- max(which(linepoints[,3]==1))
  stopifnot(lastOuter < nrow(linepoints)) # because there should be at least one inner intersection
  # now we have a point that will work..it may already be in the diagram but if not must inject it
  op <- linepoints[lastOuter,1:2,drop=FALSE]
  opName <- .find.point.in.diagram(drawing,op)
  if (is.na(opName)) {
    opEdge <- strsplit(rownames(op),";")[[1]][1]
    nix <- .node.number.unused(drawing)
    opName <- paste("e",nix,sep="")
    rownames(op) <- opName
    drawing <- injectPoint(drawing,opEdge,op)
  } else {
    rownames(op) <- opName
  }
  ip <- linepoints[lastOuter+1,1:2,drop=FALSE]
  ipName <- .find.point.in.diagram(drawing,ip)
  if (is.na(ipName)) {
    ipEdge <- strsplit(rownames(ip),";")[[1]][1]
    nix <- .node.number.unused(drawing)
    ipName <- paste("e",nix,sep="")
    rownames(ip) <- ipName
    drawing <- injectPoint(drawing,ipEdge,ip)
  } else {
    rownames(ip) <- ipName
  }

  xy <- do.call(rbind,drawing@nodeList[c(opName,ipName)])
  testEdge <- newEdgeLines(from=opName,to=ipName,xy=xy,visible=FALSE)
  stopifnot(!.internal.edge.drawing.intersection(drawing,testEdge))

  edgeName <- paste(opName,ipName,"invisible",sep="|")
  tel <- list(testEdge); names(tel) <- edgeName
  drawing@edgeList <- c(drawing@edgeList,tel)
  return(list(edgeName=edgeName,drawing=drawing,ok=TRUE))

}
#'@export
.probe.chord.intersections <- function(drawing,faceName,chord.from.xy,chord.to.xy)  {
  # given two points, chord.from.xy outside the face, and a second point chord.to.xy,
  # draw a line between the two, and see where the line intersects the face.
  # then arrange all of these intersection points in the order they appear in along the line,
  # including the chord.from.xy point



  # names pc and pmid not used
  chord <- newEdgeLines(from="pc",to="pmid",xy=rbind(chord.from.xy,chord.to.xy))

  foundList <- list()

  for ( edgeName in unique(.faceEdgeNames(drawing,faceName,unsigned=TRUE)) ) {
    faceEdge <- drawing@edgeList[[edgeName]]
    found <- .findIntersection(chord,faceEdge)
    foundList[[edgeName]] <- found
  }
  # now we have a collection of points at which the chord crosses the face
  ipoints <- do.call(rbind,lapply(names(foundList),
                                  function(x){
                                    y<-foundList[[x]];
                                    if(nrow(y)>0){rownames(y)<-paste(x,seq_len(nrow(y)),sep=";")};y})
  )
  # we want to order them along the line of the chord
  npoints <- rbind(ipoints,chord.from.xy)

  bottom <- npoints[npoints[,2]==min(npoints[,2]),,drop=FALSE]
  bottomleft <- bottom[bottom[,1]==min(bottom[,1]),,drop=FALSE]

  dist <- (npoints[,1]-bottomleft[1])^2+(npoints[,2]-bottomleft[2])^2
  npoints <- npoints[order(dist),,drop=FALSE]
  npoints

}


#'@export
.addIntersectingFace <- function(new1,new2,tempface2Name,face2IntersectionPoints) {
  # for each intersection point there is a (set of) edges of face2 to the next intersection
  # point that we need to add as a (multiple) edge
  #
  faceEdgeList <- .SplitFaceAtintersections(new2,tempface2Name,face2IntersectionPoints)
  set2Name  <- names(new2@setList)[1]

  # now each element of faceEdgeList is a set of edges from one intersection point to another
  # if we had edges duplicated between drawing1 and 2, dont need to add them in ( I think)

  currentFaceEdges <- do.call(c,lapply( .faceNames(new1), .faceEdgeNames,drawing=new1))
  seenEdges <- lapply(faceEdgeList,function(flist){flist %in% currentFaceEdges})
  lapply(seenEdges,function(seen){if (length(seen)>1 & !all(seen==seen[1])){stop("Some edges seen others not")}})
  seenEdges <- sapply(seenEdges,all)
  faceEdgeList <- faceEdgeList[!seenEdges]

  for (edgeSet in faceEdgeList) {
    #cat("Adding edge", edgeSet,"\n")
    new1 <- injectEdge(drawing=new1,newEdgeList=new2@edgeList[edgeSet],set2Name=set2Name,addToList=FALSE)
    #show(new1)
  }
  # that will have split and correctly renamed all the faces of drawing1 that the edges passed through
  # we need to catch any others
  faceNames <- .faceNames(new1,onlyVisible=TRUE)
  faceSignatures <- .faceSignatures(new1,onlyVisible=TRUE)
  nSets <- length(new1@setList)
  unchangedFaces <- faceNames[!sapply(faceSignatures ,function(x)nchar(x)==length(new1@setList))]
  for (faceName in unchangedFaces) {
    if (.is.face.within.set(drawing=new1,faceName=faceName,setName=set2Name)) {
      suffix <- "1"
    } else {
      suffix <- "0"
    }
    newFaceName<- paste(faceName,suffix,sep="")
    new1 <- renameFaces(new1,faceName,newFaceName)
    new1 <- updateSignature(new1,newFaceName,suffix)
  }
  new1
}
#'@export
.SplitFaceAtintersections <- function(new2,tempface2Name,face2IntersectionPoints) {
  face2Points <- .points.of.face(drawing=new2,tempface2Name)
  ixpoints <- sapply(face2Points,function(x){x%in%face2IntersectionPoints})

  # breaks the face into a list of edge-lists, each starting and finishing at an intersection point as defined by logical vector ixpoints
  ix <- min(which(ixpoints))
  # rearrange edges so the first one starts at an intersection point
  new2 <- .startFaceAtPoint(drawing=new2,faceName=tempface2Name,from=.points.of.face(new2,tempface2Name)[ix])
  # then recalculate
  face2Points <- .points.of.face(drawing=new2,tempface2Name)
  # now first member of point list is an intersection point
  ixstart <- which(sapply(face2Points,function(x){x%in%face2IntersectionPoints}))
  ixend <- (ixstart-1)
  ixend <- c(ixend[-1],length(face2Points))
  faceEdgeNames <- .faceEdgeNames(drawing=new2,tempface2Name)
  faceEdgeList <- list()
  for (ix in 1:length(ixstart)) {
    faceEdgeList[[ix]] <- faceEdgeNames[ seq(ixstart[ix],ixend[ix]) ]
  }
  faceEdgeList
}

#'@export
.internal.edge.drawing.intersection <- function(drawing,edge) {
  for (edgeName in names(drawing@edgeList)) {
    found <- .findIntersection(edge1=drawing@edgeList[[edgeName]],edge2=edge)
    # all the intersections, want to exclude from and to points
    fxy <- drawing@nodeList[[edge@from]]; txy <- drawing@nodeList[[edge@to]]
    if(nrow(found)>0) {
      isf <- sapply(seq_len(nrow(found)),function(ix){isTRUE(all.equal(as.numeric(found[ix,,drop=FALSE]),as.numeric(fxy)))})
      ist <- sapply(seq_len(nrow(found)),function(ix){isTRUE(all.equal(as.numeric(found[ix,,drop=FALSE]),as.numeric(txy)))})
      found <- found[!isf & !ist,,drop=FALSE]
    }
    if (nrow(found)>0) {
      return(TRUE)
    }
  }
  return(FALSE)
}
#'@export
.find.point.in.nodelist <- function(drawing,point.xy) {
  existing.xy <- do.call(rbind,drawing@nodeList)
  dist <- existing.xy;
  dist[,1] <- dist[,1]-point.xy[1]; dist[,2] <- dist[,2]-point.xy[2]
  d2 <- apply(	dist^2,1,sum)
  iszero <- which(d2 <  (.Machine$double.eps ^ 0.5))
  if (length(iszero)==0) { return(NA) }
  return(names(drawing@nodeList)[iszero])
}
#'@export
.find.duplicate.point <- function(drawing1,drawing2,pointName) {
  .find.point.in.nodelist(drawing1,drawing2@nodeList[[pointName]])
}
#'@export
.node.number.unused <- function(drawing) {
  max(as.numeric(gsub("[^0-9]","",c(names(drawing@nodeList)))))+1
}
#'@export
.add.intersection.points <- function(drawing1,drawing2) {
  new1 <- drawing1; new2 <- drawing2;
  intersectionPoints <- character(0);
  # max number used in nodenames to avoid clashes
  nix <- max(.node.number.unused(drawing1),.node.number.unused(drawing2))
  fres <- NULL
  for (edgeName1 in names(drawing1@edgeList)) {
    for (edgeName2 in names(new2@edgeList)) {
      #{cat(sprintf("looking for intersections between %s and %s\n",edgeName1,edgeName2));}
      found <- .findIntersection(edge1=drawing1@edgeList[[edgeName1]],edge2=new2@edgeList[[edgeName2 ]])
      #if(nrow(found)>0){cat(sprintf("Intersections between %s and %s\n",edgeName1,edgeName2));show(found)}
      # check if any of those were intersections we already had names for
      if(nrow(found)>0) {
        n1nodes <- apply(found,1,.find.point.in.nodelist,drawing=new1)
        n2nodes <- apply(found,1,.find.point.in.nodelist,drawing=new2)
        rownames(found) <-  paste("i",nix+seq_len(nrow(found)),sep="")
        nix <- nix + nrow(found)
        colnames(found)<- NULL
        rownames(found)[!is.na(n2nodes)] <- n2nodes[!is.na(n2nodes)]
        rownames(found)[!is.na(n1nodes)] <- n1nodes[!is.na(n1nodes)]
        new2nodes <- unique(rownames(found)[is.na(n2nodes)])
        new1nodes <- unique(rownames(found)[is.na(n1nodes)])
        found <- found[!duplicated(rownames(found)),,drop=FALSE]
        #show(found)
        #show(n1nodes)
        #show(n2nodes)
        found.df <- data.frame(found); colnames(found.df) <- c("x","y")
        found.df$nodeName <- rownames(found)
        found.df$edgeName1 <- edgeName1
        found.df$edgeName2 <- edgeName2
        if (is.null(fres)) { fres <- found.df } else {
          fres <- rbind(fres,found.df)
        }
      }
    }
  } #edgeName1
  # we have to store them up and then add them all at once so the edge names dont change as we are finding the
  if (is.null(fres)) {
    res <- list(new1=new1,new2=new2,intersectionPoints=character(0));
  } else {
    #browser()
    rownames(fres) <- 1:nrow(fres)
    fres <- fres[!duplicated(fres$nodeName),]
    for (edgeName1 in unique(fres$edgeName1)) {
      found1 <- fres[fres$edgeName1==edgeName1,]
      found1 <- subset(found1, !found1$nodeName %in% names(new1@nodeList))
      newPoints <- data.matrix(found1 [,c("x","y")]); rownames(newPoints ) <- found1$nodeName
      new1 <- injectPoints(drawing=new1 ,edgeName=edgeName1,newPoints=unique(newPoints))
    }
    for (edgeName2 in unique(fres$edgeName2)) {
      found2 <- fres[fres$edgeName2==edgeName2,]
      found2 <- subset(found2, !found2$nodeName %in% names(new2@nodeList))
      newPoints <- data.matrix(found2 [,c("x","y")]); rownames(newPoints ) <- found2$nodeName
      new2 <- injectPoints(drawing=new2 ,edgeName=edgeName2,newPoints=unique(newPoints) )
    }
    intersectionPoints <- unique(fres$nodeName)
    res <- list(new1=new1,new2=new2,intersectionPoints=intersectionPoints);
  }
  res
}

#'@export
.node.distance <- function(xy1,xy2) {
  distmat <- matrix(NA,nrow=nrow(xy1),ncol=nrow(xy2))
  for (i in seq_len(nrow(xy1))) {
    for (j in seq_len(nrow(xy2))) {
      distmat[i,j] <- sqrt(sum((xy1[i,] - xy2[j,])^2))
    }
  }
  distmat
}
#'@export
.nodes.identical <- function(xy1,xy2) {
  stopifnot(nrow(xy2)==1)
  distmat <- .node.distance(xy1,xy2)
  idmat <- abs(distmat) < (.Machine$double.eps ^ 0.5)
  wix <- which(idmat)
  if(length(wix)==0) { return(NA) }
  return(min(wix))
}

#'@export
.check.clashes <- function(drawing1,drawing2) {
  if (any(names(drawing2@setList) %in% names(drawing1@setList))) {
    stop("Clashing set names")
  }
  # now we add all the nodes from new2 in
  new2 <- drawing2
  # do we have nodes with the same name but at different places?
  newNodes <- names(new2@nodeList)
  oldNodes <- newNodes[newNodes %in% names(drawing1@nodeList)]
  newNodes <- newNodes[!newNodes %in% names(drawing1@nodeList)]
  for (node in oldNodes) {
    p.1 <- drawing1@nodeList[[node]];
    p.2 <- new2@nodeList[[node]]
    nix <- .nodes.identical(p.1,p.2);
    if (is.na(nix)) {
      stop(sprintf("Node %s is different in two drawings",node))
    }
  }
  # or nodes which have different names but in the same place?
  for (node in newNodes) {
    p.1 <- do.call(rbind,drawing1@nodeList);
    p.2 <- new2@nodeList[[node]]
    nix <- .nodes.identical(p.1,p.2);
    if (!(is.na(nix))) {
      #			cat(sprintf("Node %s is the same as %s;\n",names(drawing1@nodeList)[nix],node))
      new2 <- rename.node(drawing=new2,oldName=node,newName=names(drawing1@nodeList)[nix])
    }
  }
  new2
}
#'@export
rename.node <- function(drawing,oldName,newName) {
  names(drawing@nodeList)[names(drawing@nodeList)==oldName] <- newName
  for (ix in seq_len(length(drawing@edgeList))) {
    if (drawing@edgeList[[ix]]@from == oldName) {
      drawing@edgeList[[ix]]@from <- newName
    }
    if (drawing@edgeList[[ix]]@to == oldName) {
      drawing@edgeList[[ix]]@to <- newName
    }
  }
  drawing
}
#'@export
.check.duplicate.edges <- function(drawing1,drawing2) {
  # first we check the forward edges....

  fromtomat1 <- sapply(drawing1@edgeList,function(y){paste(y@from,y@to)})
  fromtomat2 <- sapply(drawing2@edgeList,function(y){paste(y@from,y@to)})
  commonfromto <- fromtomat2 %in% fromtomat1
  common2 <- fromtomat2[commonfromto]
  common1 <- lapply(common2,function(x)fromtomat1[fromtomat1==x])
  for (edgeName2 in names(common1)) {
    edgeNames1 <- names(common1[[edgeName2]])
    edges1 <- drawing1@edgeList[edgeNames1]
    edge2 <- drawing2@edgeList[[edgeName2]]
    for (edgeName1 in names(edges1)) {
      edge1 <- edges1[[edgeName1]]
      if (.identical(edge1,edge2)) {
        #cat(sprintf("Replacing edge %s by %s\n",edgeName2,edgeName1))
        drawing2 <- .rename.edge(drawing2,edgeName2,edgeName1)
        if (edgeName2 %in% names(drawing1@edgeList)) {
          drawing1@edgeList[[edgeName2]] <- NULL
        }
        #show(names(drawing1@edgeList))
        #cat("==----\n")
        #show(names(drawing2@edgeList))
        #cat("======\n")
      }
    }
  }
  # then the reverse
  fromtomat1 <- sapply(drawing1@edgeList,function(y){paste(y@from,y@to)})
  fromtomat2 <- sapply(drawing2@edgeList,function(y){paste(y@to,y@from)}); # nb reverse fromto
  commonfromto <- fromtomat2 %in% fromtomat1
  common2 <- fromtomat2[commonfromto]
  common1 <- lapply(common2,function(x)fromtomat1[fromtomat1==x])
  for (edgeName2 in names(common1)) {
    edgeNames1 <- names(common1[[edgeName2]])
    edges1 <- drawing1@edgeList[edgeNames1]
    edge2 <- .reverseEdge(drawing2@edgeList[[edgeName2]]) # nb reverse
    for (edgeName1 in names(edges1)) {
      edge1 <- edges1[[edgeName1]]
      if (.identical(edge1,edge2)) {
        #cat(sprintf("Replacing edge %s by %s\n",edgeName2,edgeName1))
        revName1<- sub("^--","",paste("-",edgeName1,sep=""))
        drawing2 <- .rename.edge(drawing2,edgeName2,revName1)
        if (edgeName2 %in% names(drawing1@edgeList)) {
          drawing1@edgeList[[edgeName2]] <- NULL
        }
        #show(names(drawing1@edgeList))
        #cat("==----\n")
        #show(names(drawing2@edgeList))
        #cat("======\n")
      }
    }
  }


  list(new1=drawing1,new2=drawing2)
}
#'@export
.rename.edge <- function(drawing,oldEdgeName,newEdgeName) {
  oldEdgeName <- sub("^-","",oldEdgeName)
  revEdgeName <- paste("-",oldEdgeName,sep="")
  revNewEdgeName <- sub("^--","",paste("-",newEdgeName,sep=""))
  names(drawing@edgeList)[names(drawing@edgeList)==oldEdgeName] <- newEdgeName
  names(drawing@edgeList)[names(drawing@edgeList)==revEdgeName ] <- revNewEdgeName

  faceNames <- .faceNames(drawing)
  for (faceName in faceNames) {
    drawing <- spliceEdgeIntoFace (drawing,faceName,oldEdgeName,newEdgeName,doReverse=TRUE)
  }

  drawing@setList <- lapply(drawing@setList ,function(flist) {
    flist[flist==oldEdgeName ] <- newEdgeName
    flist[flist==revEdgeName ] <- revNewEdgeName
    flist
  })
  drawing
}
#'@export
remove.nonintersectionpoints <- function(drawing) {
  # a non intersection point is a named point (usually from when the face was a single edge)
  # at which there are no intersections with any other sets/invisible edges
  # ie it is at the end of exactly one edge
  #browser()
  # rely on having only the edges in the drawing in the edgelist, and only have one of each orientation
  toNodes <- lapply(drawing@edgeList,function(x)x@to)
  fromNodes <- lapply(drawing@edgeList,function(x)x@from)
  toNode.count <- table(as.character(toNodes))
  fromNode.count <- table(as.character(fromNodes))
  noni.nodes <- intersect(names(toNode.count)[toNode.count==1],names(fromNode.count)[fromNode.count==1])
  for (node in noni.nodes) {
    inedgeName <- names(toNodes)[toNodes==node]
    outedgeName<- names(fromNodes)[fromNodes==node]
    drawing <- joinEdgesInDrawing(drawing,inedgeName ,outedgeName)
  }
  drawing
}
#'@export
getEdge <- function(drawing,edgeName) {
  edgeUnsigned <- sub("^-","",edgeName)
  edge <- drawing@edgeList[[edgeUnsigned]]
  if (edgeUnsigned != edgeName) {
    edge <- .reverseEdge(edge)
  }
  edge
}
#'@export
joinEdgesInDrawing <- function(drawing,inedgeName ,outedgeName) {
  inrev <- substr(inedgeName,1,1)=="-"
  outrev <- substr(outedgeName,1,1)=="-"
  if (inrev !=outrev) {stop("Cant cope with joining edges of opposite polarity")}
  if (!inrev){
    inpos <- inedgeName; inneg <- paste("-",inedgeName,sep="")
    outpos <- outedgeName; outneg <- paste("-",outedgeName,sep="")
  }	else {
    inpos <- sub("^-","",outedgeName);inneg<- outedgeName
    outpos <- sub("^-","",inedgeName); outneg <- inedgeName
  }
  inedge <- getEdge (drawing,inpos)
  outedge <-getEdge (drawing,outpos)
  if (inedge@to != outedge@from) { stop(sprintf("Edges do not joint at single point: %s,%s\n",inedge@to,outedge@from))}
  if (class(inedge) != class(outedge)) { stop(sprintf("Cant join edges of different classes")) }
  #if (class(inedge) != "VDedgeLines") {stop(sprintf("Cant join edges of non edgeLine classes")) }


  newEdge <- joinEdges(inedge,outedge)

  inEdgeSplit <- strsplit(inedgeName ,split="|",fixed=TRUE)[[1]];
  if (length(inEdgeSplit)>=3) {
    Set <- inEdgeSplit[3]
  } else {
    Set <- "X"
  }
  #cat(sprintf("Joining %s and %s in Set %s\n",inedgeName,outedgeName,Set))
  newEdgeName <- paste(inedge@from,outedge@to,gsub("[A-Za-z]","",Set),sep="|")

  drawing@edgeList[[ inpos]] <- NULL
  drawing@edgeList[[ outpos]] <- NULL
  drawing@edgeList[[ newEdgeName]]  <- newEdge
  for (setName in names(drawing@setList)) {
    fedges <- .faceEdgeNames(drawing,setName,type="set")
    if (fedges[1]==outpos) { fedges <- fedges[c(2:length(fedges),1)] }
    fedges <- spliceinstead(fedges,c(inpos,outpos),newEdgeName)
    drawing@setList[[setName]] <- fedges
  }
  for (fname in .faceNames(drawing)) {
    fedges <- .faceEdgeNames(drawing,fname,type="face")
    # first look for +ve pairs
    if (fedges[1]==outpos) { fedges <- fedges[c(2:length(fedges),1)] }
    fedges <- spliceinstead(fedges,c(inpos,outpos),newEdgeName)
    # then negative ones
    if (fedges[1]==inneg){ fedges <- fedges[c(2:length(fedges),1)] }
    revName <- paste("-",newEdgeName,sep="")
    fedges <- spliceinstead(fedges,c(outneg,inneg),revName)
    drawing@faceList[[fname]] <- fedges
  }
  drawing@nodeList[[inedge@to]] <- NULL
  drawing
}
#'@export
.merge.faces.invisibly.split <- function(diagram) {
  doneamerge<- TRUE
  while (doneamerge) {
    res <- .try.merge.faces.invisibly.split(diagram)
    doneamerge <- res$merged
    diagram <- res$diagram
  }
  diagram
}
#'@export
.try.merge.faces.invisibly.split <- function(diagram) {
  # first we identify multople faces with the same signature
  fsigs <- data.frame(cbind(Name=unlist(.faceNames(diagram)),Signature=unlist(.faceSignatures(diagram))),stringsAsFactors=FALSE);
  rownames(fsigs)<- 1:nrow(fsigs)
  nSets <- unique(nchar(setdiff(fsigs$Signature,"DarkMatter")))
  fsigs$Signature[fsigs$Signature==paste(rep("0",nSets),collapse="")] <- "DarkMatter"
  FacesPerSignature <- lapply(split(fsigs$Name,fsigs$Signature),length)
  FacesPerSignature <- FacesPerSignature [FacesPerSignature >1]
  doingamerge <- FALSE
  if (length(FacesPerSignature )>0) {
    for (wn in names(FacesPerSignature )) {
      wnames <- fsigs$Name[fsigs$Signature==wn]
      if (length(wnames)!=2) { warning("Can't merge multiple invisibly split faces, just trying first two")}
      faceEdges1 <- .face.to.faceEdges(diagram,wnames[1])
      faceVisible1 <- sapply(faceEdges1,function(x)x@visible)
      if (all(faceVisible1)) { break; }
      faceEdges2 <- .face.to.faceEdges(diagram,wnames[2])
      faceVisible2 <- sapply(faceEdges2,function(x)x@visible)
      if (all(faceVisible2)) { break; }
      commonInvisibleEdges <- intersect(sub("^-","",names(faceEdges1)),sub("^-","",names(faceEdges2)))
      if (length(commonInvisibleEdges)==0) break;
      doingamerge <- TRUE
      firstVisibleIx <- min(which(faceVisible1))
      firstVisibleFrom <- faceEdges1[[firstVisibleIx ]]@from
      diagram<- .startFaceAtPoint(diagram,wnames[1],firstVisibleFrom )
      faceEdges1 <- .face.to.faceEdges(diagram,wnames[1])
      faceVisible1 <- sapply(faceEdges1,function(x)x@visible)
      faceEdges2 <- .face.to.faceEdges(diagram,wnames[2])
      faceVisible2 <- sapply(faceEdges2,function(x)x@visible)
      Invisibles1 <-names( faceEdges1)[!faceVisible1]
      Invisibles2 <- rev(sub("^--","",paste("-",Invisibles1,sep="")))
      faceEdgeNames1 <- .faceEdgeNames(diagram,wnames[1])
      faceEdgeNames2 <- .faceEdgeNames(diagram,wnames[2])
      firstInvisibleIx1 <-  min(which(!faceVisible1))
      lastInvisibleIx1 <-  max(which(!faceVisible1))
      beforeNames1 <- faceEdgeNames1[1:(firstInvisibleIx1-1)]
      afterNames1 <- if(lastInvisibleIx1 <length(faceEdgeNames1)) { faceEdgeNames1[(lastInvisibleIx1+1) :length(faceEdgeNames1)] } else {character(0)}
      firstInvisibleIx2 <-  min(which(!faceVisible2))
      lastInvisibleIx2 <-  max(which(!faceVisible2))
      beforeNames2 <- if(firstInvisibleIx2 >1)faceEdgeNames2[1:(firstInvisibleIx2 -1)]else { character(0)}
      afterNames2 <- if(lastInvisibleIx2 <length(faceEdgeNames2)) { faceEdgeNames2[(lastInvisibleIx2+1) :length(faceEdgeNames2)]	} else {character(0)}

      newEdgeNames <- c(beforeNames1,afterNames2,beforeNames2,afterNames1)
      diagram@faceList[[wnames[1]]] <- newEdgeNames
      diagram@faceList[[wnames[2]]] <- NULL
      diagram@faceSignature[[wnames[2]]] <- NULL
      lostedges <- unique(sub("^-","",c(Invisibles1 ,Invisibles2)))
      diagram@edgeList[lostedges] <- NULL
    }
  }
  return(list(diagram=diagram,merged=doingamerge))
}



setGeneric("PlotUniverse",function(object,gp){standardGeneric("PlotUniverse")})
#setGeneric("IntersectionMidpoints",function(object){standardGeneric("IntersectionMidpoints")})
#setGeneric("SetLabelPositions",function(object){standardGeneric("SetLabelPositions")})
setGeneric("Areas",function(object){standardGeneric("Areas")})
setGeneric("ComputeAreas",function(object,nintervals){standardGeneric("ComputeAreas")})
setGeneric("VisibleRange",function(object){standardGeneric("VisibleRange")})
setGeneric("VennGetUniverseRange",function(object){standardGeneric("VennGetUniverseRange")})
setGeneric("VennSetUniverseRange",function(object,universe){standardGeneric("VennSetUniverseRange")})
setGeneric("VennSetSetLabels",function(object,SetLabels){standardGeneric("VennSetSetLabels")})
setGeneric("VennGetSetLabels",function(object){standardGeneric("VennGetSetLabels")})
setGeneric("VennSetFaceLabels",function(object,FaceLabels){standardGeneric("VennSetFaceLabels")})
setGeneric("VennGetFaceLabels",function(object){standardGeneric("VennGetFaceLabels")})



setClass("VennDrawing",representation("TissueDrawing","Venn",
                                      universe="matrix",SetLabels="data.frame",FaceLabels="data.frame"))

setMethod("show","VennDrawing",function(object) {
  show(as(object,"Venn"))
  show(as(object,"TissueDrawing"))
  invisible(	object)
})

setMethod("VennGetUniverseRange","VennDrawing",function(object)object@universe)
setMethod("VennSetUniverseRange","VennDrawing",function(object,universe){object@universe<-universe;object})
setMethod("VisibleRange","TissueDrawing",function(object){
  dxxy <- do.call("rbind",lapply(names(object@setList),.face.toxy,type="set",drawing=object))
  apply(dxxy,2,range)
})
#'@export
.default.SetLabelPositions <- function(object){
  yscale <- diff(VisibleRange(object)[,2]); smidge <- 0.01*yscale
  sxxy <- lapply(names(object@setList),.face.toxy,type="set",drawing=object)
  setNames <- VennSetNames(as(object,"Venn"))
  smaxy <- do.call(rbind,lapply(sxxy,function(x){x[which(x[,2]==max(x[,2]))[1],] }))
  VLabels <- data.frame(Label=rep("unset",nrow(smaxy)),x=NA,y=NA,hjust=I("left"),vjust=I("bottom"))
  VLabels[,2:3] <- smaxy
  VLabels$Label <- setNames
  VLabels
}
#'@export
setMethod("VennSetSetLabels","VennDrawing",function(object,SetLabels) {object@SetLabels <- SetLabels; object})
#'@export
setMethod("VennGetSetLabels","VennDrawing",function(object) {object@SetLabels})
#'@export
setMethod("VennSetFaceLabels","VennDrawing",function(object,FaceLabels) {object@FaceLabels <- FaceLabels; object})
#'@export
setMethod("VennGetFaceLabels","VennDrawing",function(object) {object@FaceLabels})
#'@export
setMethod("PlotUniverse","VennDrawing", function(object,gp) {
  if(missing(gp)) { gp <- NULL }
  uv <- VennGetUniverseRange(object)
  grid.rect(x=mean(uv[,1]),y=mean(uv[,2]),
            width=diff(uv[,1]),height=diff(uv[,2]),default.units="native",gp=gp)
}
)
#'@export
.square.universe <- function(object,doWeights=FALSE,smudge=0.05) {
  if (FALSE & doWeights) { # never attempt to weight the Dark Matter for now
    # minimal square box
    minimal.square.universe.area <- diff(VisibleRange(object)[,1])*diff(VisibleRange(object)[,2])
    V <- as(object,"Venn")
    visible.area <- .WeightVisible(V)
    dark.matter.area <- .WeightUniverse(V) - .WeightVisible(V)
    dark.matter.scale.squared <- (dark.matter.area + visible.area)/minimal.square.universe.area
    if (is.na(dark.matter.scale.squared) | dark.matter.scale.squared  < 1 + smudge) {
      #		warning("Square box is too large for the weight")
      dark.matter.scale.squared <- 1 + smudge
    }
  } else {
    dark.matter.scale.squared <- 1.2
  }
  dark.matter.scale <- sqrt(dark.matter.scale.squared)
  delta <- apply(VisibleRange(object),2,diff) * (dark.matter.scale-1)
  universe <- VisibleRange(object)
  universe <- universe+matrix(c(-delta,delta),ncol=2,byrow=TRUE)

  object@universe <- universe
  object
}
#'@export
CreateViewport <- function(object) {
  xData <- VennGetUniverseRange(object)[,1]
  yData <- VennGetUniverseRange(object)[,2]
  makevp.eqsc(xData,yData)
}
#'@export
UpViewports <- function() {
  upViewport()
  upViewport()
  upViewport()
}
#'@export
VennThemes<- function(drawing,colourAlgorithm,increasingLineWidth) {
  gpList <- list()
  if (is.null(gpList[["Face"]])) {
    gpList[["Face"]]<- FaceColours(drawing=drawing,colourAlgorithm=colourAlgorithm)
  }
  if (is.null(gpList[["FaceText"]])) {
    gpList[["FaceText"]] <- FaceTextColours(drawing=drawing,colourAlgorithm=colourAlgorithm)
  }
  if (is.null(gpList[["Set"]])) {
    gpList[["Set"]] <- SetColours(drawing=drawing,colourAlgorithm=colourAlgorithm,increasingLineWidth)
  }
  if (is.null(gpList[["SetText"]])) {
    gpList[["SetText"]] <- SetTextColours(drawing=drawing)
  }
  gpList
}
#'@export
FaceColours <- function(drawing,faceNames,colourAlgorithm) {
  if(missing(faceNames)) {
    faceNames <- .faceNames(drawing)
  }
  faceSignatures <- .faceSignatures(drawing)[faceNames]
  sigs <- setdiff(faceSignatures,"DarkMatter"); nSets <- max(nchar(sigs))
  faceSignatures[faceSignatures == "DarkMatter"] <-  paste(rep("0",nSets),collapse="")
  #nSets <-NumberOfSets(drawing)
  nFaces <- length(faceNames)
  nSignatures <- length(unique(faceSignatures))
  DarkMatterColour <- "pink"
  setcounts <- sort(sapply(faceSignatures,function(sig){
    sigs <- strsplit(sig,"")[[1]]
    setcount <- sum(as.numeric(sigs))
    setcount
  }))
  if (missing(colourAlgorithm)) {
    #if ( nSignatures > 12) {
      colourAlgorithm <- "signature"
    # } else {
    #  colourAlgorithm <- "sequential"
    #}
  }
  if (colourAlgorithm=="signature") {
    countmax <- max(setcounts)
    fillcols <- c(DarkMatterColour , brewer.pal(countmax,'Reds'))
    setcolours <-fillcols[1+setcounts]; names(setcolours) <- names(setcounts)
  } else if (colourAlgorithm=="sequential"){
    fillcols <- brewer.pal(12,"Set3")
    if (nSignatures > length(fillcols)) {
      fillcols <- rep(fillcols,times=1+nSignatures/length(fillcols))
    }
    setcolours <- c(DarkMatterColour,fillcols)[1:length(setcounts)]
    names(setcolours ) <- names(setcounts)
  } else if (colourAlgorithm=="binary"){
    setcolours <- ifelse(setcounts %%2 == 0 , "white", "blue")
  }

  gp <- lapply(names(faceSignatures),function(x)gpar(col=setcolours [x],fill=setcolours [x],lty=0));
  names(gp) <- names(faceSignatures)
  gp
}

#'@export
FaceTextColours <- function(drawing,faceNames,colourAlgorithm) {
  gp <- FaceColours(drawing=drawing,faceNames=faceNames,colourAlgorithm=colourAlgorithm)
  if (!missing(colourAlgorithm)) {
    if ( colourAlgorithm=="binary") {
      bcols <- unique(sapply(gp,function(x)x$col))
      stopifnot(length(bcols)==2)
      gp <- lapply(gp,function(agp){
        res<-agp;
        res$col<- if (res$col==bcols[1]){bcols[2]}else{bcols[1]};
        res$fill<-res$col;res})
    } else {
      gp <- lapply(gp,function(agp){res<-agp;res$col<-"black";res$fill<-res$col;res})
    }
  } else {
    gp <- lapply(gp,function(agp){res<-agp;res$col<-"black";res$fill<-res$col;res})
  }
  Nsets <- NumberOfSets(drawing)
  fontsize <- if (Nsets<=3) { 20 } else {10 }
  gp <- lapply(gp,function(agp){res<-agp;res$fontsize<-fontsize;res})
  gp
}

SetTextColours <- function(drawing) {
  gp <- SetColours(drawing=drawing)
  #	gp <- lapply(gp,function(agp){res<-agp;res$col<-"black";res$fill<-res$col;res})
  Nsets <- NumberOfSets(drawing)
  fontsize <- if (Nsets<=3) { 20 } else {10 }
  gp <- lapply(gp,function(agp){res<-agp;res$fontsize<-fontsize;res})
  gp
}

#'@export
SetColours <- function(drawing,colourAlgorithm,increasingLineWidth) {
  if (missing(colourAlgorithm)) { colourAlgorithm <- "sequential"}
  if (missing(increasingLineWidth)) { increasingLineWidth <- FALSE}
  nSets <-length(drawing@setList)
  if (colourAlgorithm=="binary") {
    setcolours <-rep("blue",nSets)
    names(setcolours) <- names(drawing@setList)
  } else {
    fillcols <- brewer.pal(9,'Set1')
    if (nSets > length(fillcols)) {
      fillcols <- rep(fillcols,times=1+nSets/length(fillcols))
    }
    setcolours <-fillcols[1:nSets];
    names(setcolours) <- names(drawing@setList)
  }
  gpList <- lapply(names(setcolours ),function(x)gpar(col=setcolours [[x]],fill=NA,lty=1,lwd=3));
  if (increasingLineWidth) {
    gpList <- lapply(1:nSets,function(x){gp <- gpList[[x]];gp$lwd <- nSets - x + 1; gp})
  }
  names(gpList ) <- names(setcolours)
  gpList
}

#'@export
PlotVennGeometry <- function(C3,gpList,show=list(FaceText="weight")) {
  show.default <- list(Universe=TRUE,Sets=TRUE,SetLabels=TRUE,
                       DarkMatter=FALSE,
                       Faces=TRUE,
                       FaceText="weight")
  unshown <- names(show)[! names(show) %in% names(show.default)]
  if (length(unshown)>0) {
    warning(sprintf("Unknown show parameters %s",paste(unshown,collapse=",")))
  }
  dmw <- Weights(C3)[dark.matter.signature(C3)]
  if (!is.na(dmw) & dmw > 0 ) {
    show.default$DarkMatter <- TRUE
  }
  show <- show[names(show) %in% names(show.default)]

  show.default[names(show)] <- show
  gp <- VennThemes(drawing=C3)
  if (!missing(gpList)) {
    for(sname in names(gpList)) {
      gp[[sname]] <- gpList[[sname]]
    }
  }


  CreateViewport(C3)

  if(show.default$Universe) {
    PlotUniverse(C3)
  }
  #	if(show.default$DarkMatter) {
  #		PlotDarkMatter(C3)
  #	}
  if (show.default$Faces) {
    PlotFaces(C3,gp=gp[["Face"]])
  }
  if(show.default$Sets) {
    PlotSetBoundaries(C3,gp=gp[["Set"]])
  }
  if(show.default$SetLabels) {
    PlotSetLabels (C3,gp=gp[["SetText"]])
  }

  if (length(show.default$FaceText)>0) {
    PlotIntersectionText(C3,element.plot=show.default$FaceText,
                         gp=gp[["FaceText"]],
                         show.dark.matter=show.default$DarkMatter)
  }

  UpViewports()
}
#'@export
setMethod("plot",signature(x="VennDrawing",y="missing"),function(x,y,...)PlotVennGeometry(C3=x,...))
#'@export
PlotIntersectionText <- function(object,gp,element.plot="weight",show.dark.matter=TRUE) {
  if (missing(gp)) gp <- FaceTextColours(object)
  V <- as(object,"Venn")
  nSets <- NumberOfSets(V)
  VI <- VennGetFaceLabels(object);
  rownames(VI) <- VI$FaceName


  VI$Annotation <- ""
  if( "weight" %in% element.plot ) {
    VI$WeightText <- ""
    weights <- Weights(V)[names(Weights(V)) %in% VI$Signature]
    for (ix in seq_along(weights)) {
      VI[VI$Signature==names(weights)[ix],"WeightText"] <- weights[ix]
    }
    VI$Annotation <- paste(VI$Annotation,VI$WeightText,sep="\n")
  }
  if ("signature" %in% element.plot |"indicator" %in% element.plot) {
    VI$Annotation <- paste(VI$Annotation,VI$Signature,sep="\n")
  }
  if ("sets" %in% element.plot ) {
    sets <- seq_len(nSets)
    setpick <- strsplit(VI$Signature,split="")
    setnums <- sapply(setpick,function(w){paste(as.character(sets[w==1]),collapse="")})
    VI$Annotation <- paste(VI$Annotation,setnums,sep="\n")
  }
  if ("elements" %in% element.plot) {
    elements <- V@IntersectionSets
    if (is.null(elements)) {
      warning("No intersection sets elements known")
      VINames <- ""
    } else {
      VINames <- sapply(elements,paste,collapse="") #
    }
    elements <- VINames[VI$Signature]
    VI$Annotation <- paste(VI$Annotation ,elements,sep="\n")
  }
  VI$Annotation <- sub("^\n","",VI$Annotation)
  if (!show.dark.matter) {
    VI <- VI[rownames(VI)!="DarkMatter",]
  }
  if (!"hjust" %in% colnames(VI)) { VI$hjust <- "centre" }
  if (!"vjust" %in% colnames(VI)) { VI$vjust <- "centre" }
  hj <-sapply( VI$hjust,function(EXPR){switch(EXPR,left=0,right=1,center=,centre=0.5)})
  vj <-sapply( VI$vjust,function(EXPR){switch(EXPR,top=1,bottom=0,center=,centre=0.5)})
  for (ij in 1:nrow(VI)) {
    grid.text(x=VI$x[ij],y=VI$y[ij],hjust=hj[ij],
              gp=gp[[VI$FaceName[ij]]],
              vjust=vj[ij],label=VI$Annotation[ij],default.units="native")
  }
}
#'@export
.default.FaceLabelPositions <- function(object){
  dm <-  dark.matter.signature(object)
  ilabels <- data.frame(internalPointsofFaces(as(object,"TissueDrawing")))
  colnames(ilabels) <- c("x","y")
  ilabels$FaceName <- rownames(ilabels)
  sigs <- unlist(.faceSignatures(object))
  sigdf <- data.frame(Signature=sigs,FaceName=names(sigs),stringsAsFactors=FALSE)
  df <- merge(sigdf,ilabels)
  df[df$FaceName=="DarkMatter","Signature"] <- dm
  df$hjust <- I("centre")
  df$vjust <- I("centre")
  df[df$Signature==dm,c("hjust")] <- c("right")
  df[df$Signature==dm,c("vjust")] <- c("top")
  df[df$Signature==dm,c("x","y")] <- VisibleRange(object)[2,]
  df
}
#'@export
setMethod("Areas","VennDrawing",function(object) {
  areas <- faceAreas(as(object,"TissueDrawing"))
  names(areas)[names(areas)=="DarkMatter"] <- dark.matter.signature(object)

  areas
})

#'@export
PlotSetLabels <- function(object,gp) {
  VLabels <- VennGetSetLabels(object)
  if(missing(gp)) gp <- SetColours(object)
  if(nrow(VLabels)==0){ warning("Can't show Set labels"); return()}
  #	print(VLabels)
  # just may not be vectorised...
  hj <-sapply( VLabels$hjust,function(EXPR){switch(EXPR,left=0,right=1,center=,centre=0.5)})
  vj <-sapply( VLabels$vjust,function(EXPR){switch(EXPR,top=1,bottom=0,center=,centre=0.5)})

  for (ij in 1:nrow(VLabels)) {
    grid.text(x=VLabels$x[ij],y=VLabels$y[ij],hjust=hj[ij],
              vjust=vj[ij],gp=gp[[ij]],label=as.character(VLabels$Label[ij]),default.units="native")
  }
}

#'@export
makevp.eqsc <- function(xrange,yrange) {
  # cf Fig 7.4 of Murrell R Graphics
  pushViewport(plotViewport(name="Vennmar",c(1,1,1,1)))
  pushViewport(viewport(name="Vennlay",layout=grid.layout(1,1,widths=diff(xrange),heights=diff(yrange),respect=TRUE)))
  pushViewport(viewport(name="Vennvp",layout.pos.row=1,layout.pos.col=1,xscale=xrange,yscale=yrange))
}
#'@export
PlotDarkMatter <- function(VD) {
  ur <- VennGetUniverseRange(VD)
  grey <- brewer.pal(8,"Greys")[2]
  grid.polygon(x=ur[c(1,1,2,2),1],y=ur[c(1,2,2,1),2],gp=gpar(fill=grey))
  .PlotFace.TissueDrawing(VD,"DarkMatter",gp=gpar(fill="white"),doDarkMatter=TRUE)
}
devradiumking/maxabpp documentation built on May 31, 2020, 9:01 a.m.