public bool attemptMerge(Region r) {
			if (normal != r.getNormal ()) {
				// We definitly can't merge a region with another normal
				return false;
			}

			foreach (Face f1 in r.getFaces()) {
				foreach (Face f2 in faces) {
					if (f1.sharesVertex(f2)) {
						mergeWithRegion (r);
						return true;
					}
				}
			}
			return false;
		}
		public void createRegionsForEdge(HighLevelEdge hle) {
			Region r1 = new Region ();
			Region r2 = new Region ();
			foreach (Edge e in hle.getEdges()) {
				foreach (Face f in e.getFaces()) {
					// Attempt to add to both regions
					if (r1.addFace (f)) {
						f.setParent (r1);
						r1.addEdge (hle);
						hle.addRegion (r1);
					} else if (r2.addFace (f)) {
						f.setParent (r2);
						r2.addEdge (hle);
						hle.addRegion (r2);
					}
				}
			}
			regions.Add (r1);
			regions.Add (r2);
		}
		public override List<MeshFilter> apply (Region r)
		{
			List<MeshFilter> meshes = new List<MeshFilter> ();
			Vector3 cornerDimensions = new Vector3 (1.0f, 1.0f, 1.0f);

			HighLevelEdge e1 = null;
			HighLevelEdge e2 = null;
			foreach (HighLevelEdge edgeFirst in r.getEdges()) {
				e1 = edgeFirst;
				foreach (HighLevelEdge edgeSecond in r.getEdges ()) {
					if (edgeSecond.Equals (e1))
						continue;
					if (
						(e1.getFrom ().Equals (edgeSecond.getFrom ()) || e1.getFrom ().Equals (edgeSecond.getTo ()))
						&& e1.getDirection ().y != edgeSecond.getDirection ().y) {
						// Same start vertex
						e2 = edgeSecond;
						break;
					}
				}
				if (e2 != null)
					break;
			}
			if (e2 == null) {
				Debug.Log ("Error - no two edges from same start vertex in region with different y values");
				return meshes;
			}
			Vector3 horizontalDir, verticalDir;
			if (e1.getDirection ().y == 0) {
				horizontalDir = e1.getDirection (e1.getFrom());
				verticalDir = e2.getDirection (e1.getFrom());
			} else {
				horizontalDir = e2.getDirection (e1.getFrom());
				verticalDir = e1.getDirection (e1.getFrom());
			}
			Corner corner = e1.getFrom ();
			Vector3 p = corner.getVertex().getPoint();
			horizontalDir = parent.TransformVector(horizontalDir);
			verticalDir = parent.TransformVector(verticalDir);
			p = parent.TransformPoint (p);

			Vector3 dimensions = this.getCellDimensions ();
			Vector3 scale = this.getCellSize ();

			float horizontalMagnitude = horizontalDir.magnitude - 3.0f;
			float verticalMagnitude = verticalDir.magnitude;

			horizontalDir = parent.InverseTransformVector (horizontalDir);
			verticalDir = parent.InverseTransformVector (verticalDir);

			verticalDir.Normalize ();
			horizontalDir.Normalize ();

			Vector3 start = p + Vector3.Scale(corner.getTranslateVector(), cornerDimensions / 2);
			start += cornerDimensions.z / 2 * horizontalDir;// + dimensions.z / 2 * horizontalDir;
			start += cornerDimensions.y / 2 * verticalDir + dimensions.y / 2 * verticalDir;

			bool brickOut = verticalDir.y < 0;

			int maxVertical = (int) (verticalMagnitude / dimensions.y) - 2;

			for (int i = 0; i < maxVertical; i++) {
				Vector3 rowStart = start + i * dimensions.y * verticalDir;
				Vector3 rowEnd = rowStart + horizontalMagnitude * horizontalDir;
				if (brickOut) {
					rowStart += 2.0f / 2 * horizontalDir;
					rowEnd += 2.0f / 2 * horizontalDir;
				}
				Vector3 normal = r.getNormal ();
				meshes.AddRange(FillCellModule.fillCell (rowStart, rowEnd, scale, dimensions, parent, color, normal));
				brickOut = !brickOut;
			}


			return meshes;
		}
		public void addRegion(Region r) {
			this.regions.Add(r);
		}
		public void setParent(Region r) {
			this.parent = r;
		}
		abstract public List<MeshFilter> apply(Region r);
		private void mergeWithRegion(Region r) {
			this.faces.AddRange(r.getFaces ());
			this.edges.AddRange(r.getEdges ());
		}