/**
* Copyright (c) 2009-2011, chunquedong(YangJiandong)
*
* This file is part of ChunMap project
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE(Version >=3)
*
* History:
* 2010-05-05 Jed Young Creation
*/
package chunmap.model.relate;
import chunmap.model.elem.Envelope;
import chunmap.model.geom.*;
import static chunmap.model.relate.IntersectionMatrix.*;
/**
* 计算两个几何体之间的关系
*
* @author chunquedong
*
*/
public abstract class ComputeIm {
protected Geometry g1;
protected Geometry g2;
protected IntersectionMatrix im;
private boolean isReverse = false;
/**
* 返回IM
*
* @return
*/
public IntersectionMatrix getIM() {
if (im == null) {
if (!g1.isValid() || !g2.isValid()) {
throw new GeometryException();
}
im = new IntersectionMatrix();
im.set(Outer, Outer, AreaDim);
computeIM();
// 转置
if (isReverse) {
im = im.reverse();
}
}
return im;
}
/**
* 对调两个几何体顺序的IM
*
* @return
*/
protected ComputeIm setReverse(boolean b) {
isReverse = b;
return this;
}
// ------------------------------------------------------------主函数
/**
* 计算IM的模板,主要方法。次方法也可能被子类覆盖以提高效率
*/
protected void computeIM() {
Envelope en1 = g1.getEnvelop();
boolean hasInte = en1.hasIntersect(g2.getEnvelop());
if (!hasInte) {
// 相离时
disjoin();
} else {
// 设置边界
setBorderIM();
// 设置内部
int iiDim = inner2innerDim(g1, g2);
im.set(Inner, Inner, iiDim);
// 设置内外,外内
setInnerOuterAndOuterInner();
}
}
// ------------------------------------------------------------辅助函数
/**
* 设置内外,外内
*
*/
private void setInnerOuterAndOuterInner() {
int dim1 = g1.getGeometryType().dimension();
int dim2 = g2.getGeometryType().dimension();
if (dim1 < dim2) {
setInnerOuter();
im.set(Outer, Inner, dim2);
} else if (dim1 > dim2) {
im.set(Inner, Outer, dim1);
setOuterInner();
} else {
setInnerOuter();
setOuterInner();
}
}
private void setInnerOuter() {
if (isDisjoin()) {
im.set(Inner, Outer, getBoundaryDimension(g1));
} else if (within(g1, g2)) {
im.set(Inner, Outer, EmptyDim);
} else {
im.set(Inner, Outer, getBoundaryDimension(g1));
}
}
/**
* @return
*/
private boolean isDisjoin() {
return im.get(Inner, Inner) == EmptyDim
&& im.get(Inner, Border) == EmptyDim;
}
private void setOuterInner() {
if (isDisjoin()) {
im.set(Inner, Outer, getBoundaryDimension(g1));
} else if (within(g2, g1)) {
im.set(Outer, Inner, EmptyDim);
} else {
im.set(Outer, Inner, getBoundaryDimension(g2));
}
}
// ------------------------------------------------------------钩子方法
//
/**
* 内部和内部的交集维度。计算时可参考边界交集。
*
* @param g1
* @param g2
* @return
*/
protected abstract int inner2innerDim(Geometry g1, Geometry g2);
//
/**
* 是否完全被包含在里面。计算时可参考IIDim,但相同维度计算不可使用边界交集。
*
* @param g1
* @param g2
* @return
*/
protected abstract boolean within(Geometry g1, Geometry g2);
// ------------------------------------------------------------相离时
/**
* 相离时设置IM
*/
private void disjoin() {
im.set(Outer, Inner, g2.getGeometryType().dimension());
im.set(Inner, Outer, g1.getGeometryType().dimension());
int bdim1 = getBoundaryDimension(g1);
int bdim2 = getBoundaryDimension(g2);
im.set(Outer, Border, bdim2);
im.set(Border, Outer, bdim1);
}
/**
* 边界维度
*
* @return
*/
private int getBoundaryDimension(Geometry g) {
Geometry b1 = g.getBoundary();
int bdim1 = (b1 == null) ? -1 : b1.getGeometryType().dimension();
return bdim1;
}
// ------------------------------------------------------------设置边界
/**
* 设置边界处的IM
*/
private void setBorderIM() {
Geometry b2 = g2.getBoundary();
if (b2 != null) {
IntersectionMatrix tim = ComputeImFactory.getInstance()
.getImComputer(g1, b2).getIM();
im.set(Inner, Border, getDim(tim, Inner));
im.set(Border, Border, getDim(tim, Border));
im.set(Outer, Border, getDim(tim, Outer));
}
Geometry b1 = g1.getBoundary();
if (b1 != null) {
IntersectionMatrix tim = ComputeImFactory.getInstance()
.getImComputer(b1, g2).getIM();
im.set(Border, Inner, getDim2(tim, Inner));
im.set(Border, Border, getDim2(tim, Border));
im.set(Border, Outer, getDim2(tim, Outer));
}
}
private int getDim(IntersectionMatrix tim, int i) {
int ii = tim.get(i, Inner);
int ib = tim.get(i, Border);
return Math.max(ii, ib);
}
private int getDim2(IntersectionMatrix tim, int i) {
int ii = tim.get(Inner, i);
int ib = tim.get(Border, i);
return Math.max(ii, ib);
}
}