/* * AbstractFuzzySet.java * * Created on 26 September 2002, 19:11 */ package uk.ac.leeds.ccg.projects.MedAction.FuzzyInference; /** * a fuzzy set consists of a few fuzzy points, provide a fuzzy member for a fuzzy variable * correspondingly, a fuzzy set looks a triangle fuzzy member or rectangle fuzzy member, the * shape of a fuzzy set depends on how many points it has. the original idea of having * this abstract class is to offer a common basis for different shape of a fuzzy set * but late on the FuzzySet could have any number of fuzzy sets if more than 3 points. * the two classes could be merged together, but it is still good to have this for other class to * extends. * * the abstractFuzzySet doesn't care about how many points it has, just abstract * the common rule a fuzzy set must have. a fuzzy set class have to extends this class * * @author Jianhui Jin */ import java.awt.geom.Point2D; import java.io.Serializable; import java.awt.Color; import uk.ac.leeds.ccg.geotools.*; import com.sun.java.util.collections.*; public abstract class AbstractFuzzySet implements Serializable { // each set has a name, which will be the member name of a varaible. private String name =""; // a set has many point depends on the shape of the set, // which will be defined by a extended FuzzySet Class. private FuzzyPoint point[]=null; // it is used by fuzzypanel's custamized paintComponent() method to paint a // fuzzy set. the non-selected will be blue, selected will be red private Color color = Color.blue; // setWidth is actually a half of the set width starting from the position above X // ending to the position at X. private double setWidth = 0.0; /** Creates a new instance of AbstractFuzzySet */ public AbstractFuzzySet() { } /** * a fuzzy set will at least has three point. * topPointX will be the X value of the top point. * a set at least has one top point. * setWidth will be distance between the position, in the lines of sets, * whoes Y is larger than 0.0, and the position whoes X is ending on the 0.0. * @return */ public final double getSetWidth() { return this.setWidth; } /** * * @param setWidth */ public final void setFuzzySetWidth( double setWidth ) { this.setWidth = setWidth; } /** * * @return the name of this fuzzy set, "High", "Very High", "Low", etc. */ public final String getName(){ return this.name; } /** * * @return the color of this set displayed in a fuzzyPanel, the difference is * between selected and unselected, the default color is for unselected, when selected * fuzzy panel will call setColor(Color c) to set another color in. */ public final Color getColor(){ return this.color; } /** * fuzzy panel will call setColor(Color c) to set another color in. * @param Color object, to be taken by fuzzy panel to paint this fuzzy set * */ public final void setColor(Color c) { this.color=c; } /** * fuzzy panel will set name for each fuzzy set in terms of the number of the fuzzy sets * in a fuzzy variable. if three sets, could be "low", "average", "high", and so on for others. * @param newName for this fuzzy Set. */ public final void setName(String newName) { this.name=newName; } /** * a basic calculation in fuzzification process is get the membership degree * for a input value in the corresponding fuzzy variable's membership functions. * each function is a fuzzy set, so put in a value in a fuzzy set, we will get the * degree of the member ("Low","high", etc. ) for this input value. * @param input * @return */ public final double getDegree(double input) { double degree=0.0; FuzzyPoint[] ps = this.getFuzzyPoint(); // this value will record where the input value fulls in after a fuzzy point in this fuzzy set, // then with the next point we can got a line intersecting the line with // input as X and paralleling with Y axis. // the degree of the input value could be got from the intersecting point's Y value int start = 0 ; // check where the input value falls in for(int i = 0 ; i < ps.length - 1 ; i++ ){ if( ( input >= ps[i].getX() ) && ( input <= ps[i+1].getX() ) ) { start = i ; break ; } } // use the two points' x and y value to get the degree // some time the two point of the line has the same x value which means // the line either is a point or a line right cross the X coordinate line // in this case, the degree should be the same value with y2 or y1 which has // the higher value double x1 = ps[start].getX(); double x2 = ps[start+1].getX(); double y1 = ps[start].getY(); double y2 = ps[start+1].getY(); if( ( x1 == x2 ) && ( y1 > y2 ) ) { degree = y1; return degree; } else if ( ( x1 == x2 ) && ( y1 <= y2 ) ) { degree = y2; return degree; } else { degree = ( y2 - y1 ) * ( input - x1 ) / ( x2 - x1 ) + y1 ; return degree; } } /** * * @return FuzzyPoint[] all the fuzzy point in this fuzzy set */ public final FuzzyPoint[] getFuzzyPoint() { return this.point; } /** * * @param value double[points][value], so double[0][0] is x value for point * double[0], double[0][1] is the y valuve the same point */ public final void setFuzzyPoint(double[][] value){ FuzzyPoint[] ps=new FuzzyPoint[value.length]; for(int i=0;i ps[ i + 1].getX() ){ ps[i].setX( ps[ i + 1 ].getX() ) ; check(); } } // for Y value, slightly complex, it needs to be increase all the time until // reaching the top, then decreas until bottom. boolean up = true; for( int i = 0 ; i < ps.length - 1 ; i++ ) { if( ps[ i ].getY() == 1.0d ) { up = false; } if( up && ( ps[ i ].getY() > ps[ i + 1 ].getY() ) ){ ps[ i ].setY( ps[ i + 1 ].getY() ) ; check(); } else if( ( !up ) && ( ps[ i ].getY() < ps[ i + 1 ].getY() ) ) { ps[ i + 1 ].setY( ps[ i ].getY() ); check(); } } // manage all the point x and y values inside the boundary of [0,1]; for( int i = 0; i< ps.length; i++ ) { if ( ps[ i ].getX() > 1.0 ) { ps[ i ].setX( 1.0d ); } if ( ps[ i ].getX() < 0.0 ) { ps[ i ].setX( 0.0d ); } if ( ps[ i ].getY() > 1.0 ) { ps[ i ].setY( 1.0d ); } if ( ps[ i ].getY() < 0.0 ) { ps[ i ].setY( 0.0d ); } } // the start and end point should be on the bottom line and the start and end point ps[0].setX(0.0); ps[ps.length-1].setX(1.0d); ps[0].setY(0.0); ps[ps.length-1].setY(0.0d); // the middle points, which could be 1 or 2 point should be on the top of any sets if( ( ps.length % 2 ) == 0 ){ ps[ps.length/2-1].setY(1); ps[ps.length/2].setY(1); } else{ ps[ps.length/2].setY(1); } } /** * getTopPoint() returns the peek point that has maximum y vlaue in the fuzzy set * if it has two or more point in the top return the middle point of them * @return */ public final FuzzyPoint getTopPoint() { FuzzyPoint[] ps=this.getFuzzyPoint(); double xPosition=0.0; int topPointCount=0; for(int i=0;i y ) ){ continue; } // find out which point of the two below the intersect point // and add it into the Vector(); if( ps[ i ].getY() > ps[ i + 1 ].getY() ) { pointVector.add( intersectedPoint ); pointVector.add( new GeoPoint( ps[i+1].getX(), ps[i+1].getY() ) ); } else { pointVector.add( new GeoPoint( ps[i].getX(), ps[i].getY() ) ); pointVector.add( intersectedPoint ); } } // finally we need to add in the final point pointVector.add( new GeoPoint( 1.0, 0.0) ); // contruct defuzzifiedPolygon Object[] pOb = pointVector.toArray(); GeoPolygon defuzzifiedPoly = new GeoPolygon(); for( int i = 0; i < pOb.length; i++ ){ defuzzifiedPoly.addPoint( ( GeoPoint ) pOb[ i ] ); } return defuzzifiedPoly; } /** * for contruct a defuzzification polygon, * we need to know the points at which the input Y value intersect with * the fuzzy set boundary. the method will * return the intersected point or null if not. */ private final GeoPoint getIntersectingPoint(FuzzyPoint p1,FuzzyPoint p2,double y){ double x1 = p1.getX(); double y1 = p1.getY(); double x2 = p2.getX(); double y2 = p2.getY(); // find the higher point double lower = y1; double higher = y2; if ( y1 > y2 ) { higher = y1; lower = y2; } // find out whether the y beyond the boundary of the line. if( ( y > higher) || ( y < lower) ) { return null; } // now we sure the y is within the boundary of the line // but there are still a little complexity about the line // it is line has a slope > 0 and < 180 degree, this is fine // but it is possible the two point overlap. or if it is a straight line // parallel it. // if the two point overlap, since we already make sure the y within the // the line, so there are only one possible that is the intersect point also // is at the same position of the two point. // if it is a line parallel with the X coordinate line // we return the point at the middle of the line // since the middle point of the two point in the overlaping case is at the same // position so the two case could be together as: if ( y2 == y1 ) { return new GeoPoint( ( x1 + x2 ) / 2, y1 ); } // then general in the case of line having a slope else { double x = ( x2 - x1 ) * ( y - y1 ) / ( y2 - y1 ) + x1; return new GeoPoint( x , y ); } } /** * * @return transfer all the fuzzypoint value to a double[][] array * double[0] double[1] will have a double[2], so double[number of points][2] * for example double[0][x] == x value of point 0. */ public final double[][] toDoubleArray() { FuzzyPoint[] p=this.getFuzzyPoint(); double[][] temp = new double[p.length][2]; for(int i=0;i