diff --git a/src/adql/parser/ADQLQueryFactory.java b/src/adql/parser/ADQLQueryFactory.java
index 5829f327e5741c0f0da6590d48a2bfcecd3f890b..d291ef4e297a1191c51e32bad90d4037f03ce605 100644
--- a/src/adql/parser/ADQLQueryFactory.java
+++ b/src/adql/parser/ADQLQueryFactory.java
@@ -372,10 +372,20 @@ public class ADQLQueryFactory {
 		return new BoxFunction(coordinateSystem, firstCoord, secondCoord, boxWidth, boxHeight);
 	}
 
+	/** @since 2.0 */
+	public BoxFunction createBox(ADQLOperand coordinateSystem, GeometryValue<GeometryFunction> center, ADQLOperand boxWidth, ADQLOperand boxHeight) throws Exception {
+		return new BoxFunction(coordinateSystem, center, boxWidth, boxHeight);
+	}
+
 	public CircleFunction createCircle(ADQLOperand coordSys, ADQLOperand coord1, ADQLOperand coord2, ADQLOperand radius) throws Exception {
 		return new CircleFunction(coordSys, coord1, coord2, radius);
 	}
 
+	/** @since 2.0 */
+	public CircleFunction createCircle(ADQLOperand coordSys, GeometryValue<GeometryFunction> center, ADQLOperand radius) throws Exception {
+		return new CircleFunction(coordSys, center, radius);
+	}
+
 	public CentroidFunction createCentroid(GeometryFunction param) throws Exception {
 		return new CentroidFunction(new GeometryValue<GeometryFunction>(param));
 	}
diff --git a/src/adql/parser/grammar/adqlGrammar201.jj b/src/adql/parser/grammar/adqlGrammar201.jj
index 9626e427fd06e43ad48356b1dbe2da4d84d62dc1..24fef4ebb2b4fa0e575cbddc8e1b39aa1c3a152b 100644
--- a/src/adql/parser/grammar/adqlGrammar201.jj
+++ b/src/adql/parser/grammar/adqlGrammar201.jj
@@ -1305,34 +1305,30 @@ DistanceFunction DistanceFunction(): { Token fct=null, end=null; DistanceFunctio
 	}
 }
 
+GeometryValue<GeometryFunction> PointValue(): { GeometryFunction p=null; ADQLColumn col=null; UserDefinedFunction udf=null; } {
+	( p=Point()
+	| p=Centroid()
+	| LOOKAHEAD(2) udf=UserDefinedFunction()
+	| col=Column() )
+	{
+		if (p != null)
+			return new GeometryValue<GeometryFunction>(p);
+		else if (udf != null){
+		  	udf.setExpectedType('G');
+			return new GeometryValue<GeometryFunction>(udf);
+		}else{
+			col.setExpectedType('G');
+			return new GeometryValue<GeometryFunction>(col);
+		}
+	}
+}
+
 DistanceFunction DistanceFunction2(): { Token fct=null, end=null; DistanceFunction gf; GeometryValue<GeometryFunction> gvp1, gvp2; GeometryFunction p1=null, p2=null; ADQLColumn col1=null, col2=null; UserDefinedFunction udf1=null, udf2=null; } {
 	try {
 		fct=<DISTANCE> <LEFT_PAR>
-		(p1=Point()|p1=Centroid()|LOOKAHEAD(2) udf1=UserDefinedFunction()|col1=Column()) 
-		{
-			if (p1 != null)
-				gvp1 = new GeometryValue<GeometryFunction>(p1);
-			else if (udf1 != null){
-			  	udf1.setExpectedType('G');
-				gvp1 = new GeometryValue<GeometryFunction>(udf1);
-			}else{
-				col1.setExpectedType('G');
-				gvp1 = new GeometryValue<GeometryFunction>(col1);
-			}
-		}
+		gvp1=PointValue() 
 		<COMMA>
-		(p2=Point()|p2=Centroid()|LOOKAHEAD(2) udf2=UserDefinedFunction()|col2=Column())
-		{
-			if (p2 != null)
-				gvp2 = new GeometryValue<GeometryFunction>(p2);
-			else if (udf2 != null){
-			  	udf2.setExpectedType('G');
-				gvp2 = new GeometryValue<GeometryFunction>(udf2);
-			}else{
-				col2.setExpectedType('G');
-				gvp2 = new GeometryValue<GeometryFunction>(col2);
-			}
-		} 
+		gvp2=PointValue()
 		end=<RIGHT_PAR>
 		{
 			gf = queryFactory.createDistance(gvp1, gvp2);
@@ -1349,45 +1345,23 @@ ADQLOperand CoordinateSystem(): { ADQLOperand coordSys=null;}{
 	{ return coordSys; }
 }
 
-GeometryFunction GeometryValueFunction(): {Token fct=null, end=null; ADQLOperand width, height; ADQLOperand[] coords, tmp; Vector<ADQLOperand> vCoords; ADQLOperand op=null; GeometryValue<GeometryFunction> gvf = null; GeometryFunction gf = null;} {
+GeometryFunction GeometryValueFunction(): {Token fct=null, end=null; ADQLOperand coordSys, width, height; ADQLOperand[] coords = null, tmp; Vector<ADQLOperand> vCoords; ADQLOperand op=null; GeometryValue<GeometryFunction> gvf = null, gvp = null; GeometryFunction gf = null;} {
 	try{
 	  
 		// BOX (deprecated since ADQL-2.1)
-		(LOOKAHEAD(BoxWithCooSys()) gf=BoxWithCooSys()
-
-		// BOX:
-		| (fct=<BOX> <LEFT_PAR> // coord_sys
-				coords=Coordinates() // coordinates
-				<COMMA> width=NumericExpression() <COMMA> height=NumericExpression() end=<RIGHT_PAR>)
-		 {gf = queryFactory.createBox(null, coords[0], coords[1], width, height);}
+		(gf=Box()
 		
 		// CENTROID:
 		| gf=Centroid()
 
-		// CIRCLE (deprecated since ADQL-2.1)
-		| LOOKAHEAD(CircleWithCooSys()) gf=CircleWithCooSys()
-		
 		// CIRCLE:
-		| (fct=<CIRCLE> <LEFT_PAR>
-				coords=Coordinates() // coordinates
-				<COMMA> width=NumericExpression() end=<RIGHT_PAR>) // radius
-		 {gf = queryFactory.createCircle(null, coords[0], coords[1], width);}
+		| gf=Circle()
 		
 		// POINT: 
 		| gf=Point()
 
 		// POLYGON (deprecated since ADQL-2.1)
-		| LOOKAHEAD(PolygonWithCooSys()) gf=PolygonWithCooSys()
-		
-		// POLYGON:
-		| (fct=<POLYGON> <LEFT_PAR>
-				{ vCoords = new Vector<ADQLOperand>(); } // coordinates
-				tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);}
-				<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);}
-				<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);}
-				(<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);})*
-				end=<RIGHT_PAR>)
-		  { gf = queryFactory.createPolygon(null, vCoords); }
+		| gf=Polygon()
 		  
 		/* // REGION (REMOVED SINCE 2.1):
 		| (fct=<REGION> <LEFT_PAR> op=StringExpression() end=<RIGHT_PAR>) {gf = queryFactory.createRegion(op);}*/
@@ -1403,10 +1377,41 @@ GeometryFunction GeometryValueFunction(): {Token fct=null, end=null; ADQLOperand
 	}
 }
 
-GeometryFunction BoxWithCooSys(): { Token fct=null, end=null; ADQLOperand coordSys; ADQLOperand width, height; ADQLOperand[] coords; } {
-	fct=<BOX> <LEFT_PAR> coordSys=CoordinateSystem() // coord_sys
-			<COMMA> coords=Coordinates() // coordinates
-			<COMMA> width=NumericExpression() <COMMA> height=NumericExpression() end=<RIGHT_PAR>
+GeometryFunction Box(): { GeometryFunction gf; } {
+	(
+		LOOKAHEAD(BoxWithPoint())
+		gf=BoxWithPoint()
+	|
+		gf=BoxWithCoords()
+	)
+	{ return gf; }
+}
+
+GeometryFunction BoxWithPoint(): { Token fct=null, end=null; ADQLOperand coordSys=null; ADQLOperand width, height; GeometryValue<GeometryFunction> center = null; } {
+	fct=<BOX> <LEFT_PAR>
+		[ coordSys=CoordinateSystem() <COMMA> ] // coord_sys (deprecated since ADQL-2.1)
+		center=PointValue()                     // center point
+		<COMMA> width=NumericExpression()       // width
+		<COMMA> height=NumericExpression()      // height
+	end=<RIGHT_PAR>
+	{
+		try {
+			GeometryFunction gf = queryFactory.createBox(coordSys, center, width, height);
+			gf.setPosition(new TextPosition(fct, end));
+			return gf;	
+		}catch(Exception ex){
+			throw generateParseException(ex);
+		}
+	}
+}
+
+GeometryFunction BoxWithCoords(): { Token fct=null, end=null; ADQLOperand coordSys=null; ADQLOperand width, height; ADQLOperand[] coords = null; } {
+	fct=<BOX> <LEFT_PAR>
+		[ coordSys=CoordinateSystem() <COMMA> ] // coord_sys (deprecated since ADQL-2.1)
+		coords=Coordinates()                    // center coordinates
+		<COMMA> width=NumericExpression()       // width
+		<COMMA> height=NumericExpression()      // height
+	end=<RIGHT_PAR>
 	{
 		try {
 			GeometryFunction gf = queryFactory.createBox(coordSys, coords[0], coords[1], width, height);
@@ -1418,10 +1423,38 @@ GeometryFunction BoxWithCooSys(): { Token fct=null, end=null; ADQLOperand coordS
 	}
 }
 
-GeometryFunction CircleWithCooSys(): { Token fct=null, end=null; ADQLOperand coordSys; ADQLOperand width; ADQLOperand[] coords; } {
-	fct=<CIRCLE> <LEFT_PAR> coordSys=CoordinateSystem() <COMMA> // coord_sys
-			coords=Coordinates() // coordinates
-			<COMMA> width=NumericExpression() end=<RIGHT_PAR> // radius
+GeometryFunction Circle(): { GeometryFunction gf; } {
+	(
		LOOKAHEAD(CircleWithPoint())
+		gf=CircleWithPoint()
+	|
+		gf=CircleWithCoords()
+	)
+	{ return gf; }
+}
+
+GeometryFunction CircleWithPoint(): { Token fct=null, end=null; ADQLOperand coordSys=null; ADQLOperand width; GeometryValue<GeometryFunction> center = null; } {
+	fct=<CIRCLE> <LEFT_PAR>
+		[ coordSys=CoordinateSystem() <COMMA> ] // coord_sys (deprecated since ADQL-2.1)
+		center=PointValue()                     // center coordinates
+		<COMMA> width=NumericExpression()       // radius
+	end=<RIGHT_PAR>
+	{
+		try {
+			GeometryFunction gf = queryFactory.createCircle(coordSys, center, width);
+			gf.setPosition(new TextPosition(fct, end));
+			return gf;	
+		}catch(Exception ex){
+			throw generateParseException(ex);
+		}
+	}
+}
+
+GeometryFunction CircleWithCoords(): { Token fct=null, end=null; ADQLOperand coordSys=null; ADQLOperand width; ADQLOperand[] coords = null; } {
+	fct=<CIRCLE> <LEFT_PAR>
+		[ coordSys=CoordinateSystem() <COMMA> ] // coord_sys (deprecated since ADQL-2.1)
+		coords=Coordinates()                    // center coordinates
+		<COMMA> width=NumericExpression()       // radius
+	end=<RIGHT_PAR>
 	{
 		try {
 			GeometryFunction gf = queryFactory.createCircle(coordSys, coords[0], coords[1], width);
@@ -1444,33 +1477,14 @@ CentroidFunction Centroid(): {Token fct=null, end=null; GeometryValue<GeometryFu
 	}
 }
 
-PointFunction Point(): {Token start, end; ADQLOperand[] coords; PointFunction pf;} {
-	// POINT (depecrated since ADQL-2.1)
-	(LOOKAHEAD(PointWithCooSys())
-		pf=PointWithCooSys()
-		{ return pf; }
-	
-	// POINT (last version - >= ADQL-2.1)
-	|
-		start=<POINT> <LEFT_PAR> coords=Coordinates() end=<RIGHT_PAR> // coordinates
-		{
-			try{
-				pf = queryFactory.createPoint(null, coords[0], coords[1]);
-				pf.setPosition(new TextPosition(start, end));
-				return pf;
-			}catch(Exception ex){
-				throw generateParseException(ex);
-			}
-		}
-	)
-}
-
-PointFunction PointWithCooSys(): {Token start, end; ADQLOperand coordSys; ADQLOperand[] coords;} {
-	start=<POINT> <LEFT_PAR> coordSys=CoordinateSystem() <COMMA> // coord_sys
-			coords=Coordinates() end=<RIGHT_PAR> // coordinates
+PointFunction Point(): {Token start, end; ADQLOperand coordSys=null; ADQLOperand[] coords; PointFunction pf;} {
+	start=<POINT> <LEFT_PAR>
+		[ coordSys=CoordinateSystem() <COMMA> ] // coord_sys (deprecated since ADQL-2.1)
+		coords=Coordinates()                    // coordinates
+	end=<RIGHT_PAR>
 	{
 		try{
-			PointFunction pf = queryFactory.createPoint(coordSys, coords[0], coords[1]);
+			pf = queryFactory.createPoint(coordSys, coords[0], coords[1]);
 			pf.setPosition(new TextPosition(start, end));
 			return pf;
 		}catch(Exception ex){
@@ -1479,14 +1493,45 @@ PointFunction PointWithCooSys(): {Token start, end; ADQLOperand coordSys; ADQLOp
 	}
 }
 
-GeometryFunction PolygonWithCooSys(): { Token fct=null, end=null; ADQLOperand coordSys; ADQLOperand[] coords, tmp; Vector<ADQLOperand> vCoords; } {
-	fct=<POLYGON> <LEFT_PAR> coordSys=CoordinateSystem() // coord_sys
-			{ vCoords = new Vector<ADQLOperand>(); } // coordinates
-			<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);}
-			<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);}
-			<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);}
-			(<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);})*
-			end=<RIGHT_PAR>
+GeometryFunction Polygon(): { GeometryFunction gf; } {
+	(
+		LOOKAHEAD(PolygonWithPoints())
+		gf=PolygonWithPoints()
+	|
+		gf=PolygonWithCoords()
+	)
+	{ return gf; }
+}
+
+GeometryFunction PolygonWithPoints(): { Token fct=null, end=null; ADQLOperand coordSys=null; GeometryValue<GeometryFunction> tmp; Vector<ADQLOperand> vCoords; } {
+	fct=<POLYGON> <LEFT_PAR>
+		[ coordSys=CoordinateSystem() <COMMA> ]  // coord_sys (deprecated since ADQL-2.1)
+		{ vCoords = new Vector<ADQLOperand>(); } // points (min. 3)
+		 tmp=PointValue() {vCoords.add(tmp);}
+		 <COMMA> tmp=PointValue() {vCoords.add(tmp);}
+		 <COMMA> tmp=PointValue() {vCoords.add(tmp);}
+		(<COMMA> tmp=PointValue() {vCoords.add(tmp);})*
+	end=<RIGHT_PAR>
+	{
+		try {
+			GeometryFunction gf = queryFactory.createPolygon(coordSys, vCoords);
+			gf.setPosition(new TextPosition(fct, end));
+			return gf;
+		}catch(Exception ex){
+			throw generateParseException(ex);
+		}
+	}
+}
+
+GeometryFunction PolygonWithCoords(): { Token fct=null, end=null; ADQLOperand coordSys=null; ADQLOperand[] coords, tmp; Vector<ADQLOperand> vCoords; } {
+	fct=<POLYGON> <LEFT_PAR>
+		[ coordSys=CoordinateSystem() <COMMA> ]  // coord_sys (deprecated since ADQL-2.1)
+		{ vCoords = new Vector<ADQLOperand>(); } // coordinates (min. 3 pairs)
+		 tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);}
+		 <COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);}
+		 <COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);}
+		(<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);})*
+	end=<RIGHT_PAR>
 	{
 		try {
 			GeometryFunction gf = queryFactory.createPolygon(coordSys, vCoords);
diff --git a/src/adql/query/operand/function/geometry/BoxFunction.java b/src/adql/query/operand/function/geometry/BoxFunction.java
index e4b429bfdc5ec5697336f94796a621f914160219..3e84e26efeedebdbadb89bbdcc60dd6e3adafae1 100644
--- a/src/adql/query/operand/function/geometry/BoxFunction.java
+++ b/src/adql/query/operand/function/geometry/BoxFunction.java
@@ -16,13 +16,15 @@ package adql.query.operand.function.geometry;
  * You should have received a copy of the GNU Lesser General Public License
  * along with ADQLLibrary.  If not, see <http://www.gnu.org/licenses/>.
  *
- * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ * Copyright 2012-2020 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
 import adql.parser.feature.LanguageFeature;
 import adql.query.ADQLObject;
+import adql.query.operand.ADQLColumn;
 import adql.query.operand.ADQLOperand;
+import adql.query.operand.function.UserDefinedFunction;
 
 /**
  * It represents the box function of the ADQL language.
@@ -66,8 +68,7 @@ import adql.query.operand.ADQLOperand;
  *
  * <p>
  * 	The function arguments may be literal values, as above, or they may be
- * 	column references, functions or expressions that returns the appropriate
- * 	datatypes.
+ * 	column references, functions or expressions that returns a POINT value.
  * </p>
  *
  * <i>
@@ -87,7 +88,7 @@ import adql.query.operand.ADQLOperand;
  * </p>
  *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.0 (07/2019)
+ * @version 2.0 (06/2020)
  */
 public class BoxFunction extends GeometryFunction {
 
@@ -95,10 +96,23 @@ public class BoxFunction extends GeometryFunction {
 	 * @since 2.0 */
 	public static final LanguageFeature FEATURE = new LanguageFeature(LanguageFeature.TYPE_ADQL_GEO, "BOX", true, "Express a box on the sky.");
 
-	/** The first coordinate of the center of this box. */
+	/** Center position.
+	 * <p><i><b>Note:</b>
+	 * 	NULL, if both {@link #coord1} and {@link #coord2} are provided.
+	 * </i></p>
+	 * @since 2.0 */
+	private GeometryValue<GeometryFunction> centerPoint;
+
+	/** The first coordinate of the center of this box.
+	 * <p><i><b>Note:</b>
+	 * 	NULL, if {@link #centerPoint} is provided.
+	 * </i></p> */
 	private ADQLOperand coord1;
 
-	/** The second coordinate of the center of this box. */
+	/** The second coordinate of the center of this box.
+	 * <p><i><b>Note:</b>
+	 * 	NULL, if {@link #centerPoint} is provided.
+	 * </i></p> */
 	private ADQLOperand coord2;
 
 	/** The width of this box (in degrees). */
@@ -118,9 +132,11 @@ public class BoxFunction extends GeometryFunction {
 	 *                   			box.
 	 * @param boxWidth				The width of this box (in degrees).
 	 * @param boxHeight				The height of this box (in degrees).
+	 *
 	 * @throws NullPointerException	If one parameter is NULL.
 	 * @throws Exception 			If there is another error.
 	 */
+	@SuppressWarnings("deprecation")
 	public BoxFunction(ADQLOperand coordinateSystem, ADQLOperand firstCoord, ADQLOperand secondCoord, ADQLOperand boxWidth, ADQLOperand boxHeight) throws NullPointerException, Exception {
 		super(coordinateSystem);
 
@@ -131,6 +147,35 @@ public class BoxFunction extends GeometryFunction {
 		coord2 = secondCoord;
 		width = boxWidth;
 		height = boxHeight;
+		centerPoint = null;
+	}
+
+	/**
+	 * Builds a BOX function.
+	 *
+	 * @param coordinateSystem		The coordinate system of the center
+	 *                        		position.
+	 * @param center				The center position.
+	 * @param boxWidth				The width of this box (in degrees).
+	 * @param boxHeight				The height of this box (in degrees).
+	 *
+	 * @throws NullPointerException	If one parameter is NULL.
+	 * @throws Exception 			If there is another error.
+	 *
+	 * @since 2.0
+	 */
+	@SuppressWarnings("deprecation")
+	public BoxFunction(ADQLOperand coordinateSystem, GeometryValue<GeometryFunction> center, ADQLOperand boxWidth, ADQLOperand boxHeight) throws NullPointerException, Exception {
+		super(coordinateSystem);
+
+		if (center == null || boxWidth == null || boxHeight == null)
+			throw new NullPointerException("All the parameters of the BOX function must be different from NULL!");
+
+		coord1 = null;
+		coord2 = null;
+		width = boxWidth;
+		height = boxHeight;
+		centerPoint = center;
 	}
 
 	/**
@@ -139,12 +184,14 @@ public class BoxFunction extends GeometryFunction {
 	 * @param toCopy		The BOX function to copy.
 	 * @throws Exception	If there is an error during the copy.
 	 */
+	@SuppressWarnings("unchecked")
 	public BoxFunction(BoxFunction toCopy) throws Exception {
 		super(toCopy);
 		coord1 = (ADQLOperand)(toCopy.coord1.getCopy());
 		coord2 = (ADQLOperand)(toCopy.coord2.getCopy());
 		width = (ADQLOperand)(toCopy.width.getCopy());
 		height = (ADQLOperand)(toCopy.height.getCopy());
+		centerPoint = (GeometryValue<GeometryFunction>)(toCopy.centerPoint.getCopy());
 	}
 
 	@Override
@@ -177,6 +224,42 @@ public class BoxFunction extends GeometryFunction {
 		return true;
 	}
 
+	/**
+	 * Gets the center point, exactly as provided.
+	 *
+	 * <p><b>IMPORTANT NOTE:</b>
+	 * 	If this {@link BoxFunction} has been initialized with a pair of
+	 * 	coordinates, this function will return NULL.
+	 * </p>
+	 *
+	 * @return	The center point of the represented box,
+	 *        	or NULL if created with a pair of coordinates.
+	 *
+	 * @since 2.0
+	 */
+	public final GeometryValue<GeometryFunction> getCenter() {
+		return centerPoint;
+	}
+
+	/**
+	 * Sets the center point.
+	 *
+	 * <p><b>WARNING:</b>
+	 * 	Calling this function will erase the single coordinates already set:
+	 * 	{@link #getCoord1()} and {@link #getCoord2()} will both return NULL.
+	 * </p>
+	 *
+	 * @param newCenter	The new center point of the represented box.
+	 *
+	 * @since 2.0
+	 */
+	public final void setCenter(final GeometryValue<GeometryFunction> newCenter) {
+		centerPoint = newCenter;
+		coord1 = null;
+		coord2 = null;
+		setPosition(null);
+	}
+
 	/**
 	 * Gets the first coordinate (i.e. right ascension).
 	 *
@@ -254,34 +337,55 @@ public class BoxFunction extends GeometryFunction {
 	}
 
 	@Override
+	@SuppressWarnings("deprecation")
 	public ADQLOperand[] getParameters() {
-		return new ADQLOperand[]{ coordSys, coord1, coord2, width, height };
+		if (centerPoint == null)
+			return new ADQLOperand[]{ coordSys, coord1, coord2, width, height };
+		else
+			return new ADQLOperand[]{ coordSys, centerPoint.getValue(), width, height };
 	}
 
 	@Override
 	public int getNbParameters() {
-		return 5;
+		return (centerPoint == null ? 5 : 4);
 	}
 
 	@Override
+	@SuppressWarnings("deprecation")
 	public ADQLOperand getParameter(int index) throws ArrayIndexOutOfBoundsException {
-		switch(index) {
-			case 0:
-				return coordSys;
-			case 1:
-				return coord1;
-			case 2:
-				return coord2;
-			case 3:
-				return width;
-			case 4:
-				return height;
-			default:
-				throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!");
+		if (centerPoint == null) {
+			switch(index) {
+				case 0:
+					return coordSys;
+				case 1:
+					return coord1;
+				case 2:
+					return coord2;
+				case 3:
+					return width;
+				case 4:
+					return height;
+				default:
+					throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!");
+			}
+		} else {
+			switch(index) {
+				case 0:
+					return coordSys;
+				case 1:
+					return centerPoint.getValue();
+				case 2:
+					return width;
+				case 3:
+					return height;
+				default:
+					throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!");
+			}
 		}
 	}
 
 	@Override
+	@SuppressWarnings({ "unchecked", "deprecation" })
 	public ADQLOperand setParameter(int index, ADQLOperand replacer) throws ArrayIndexOutOfBoundsException, NullPointerException, Exception {
 		if (replacer == null)
 			throw new NullPointerException("Impossible to remove one parameter from a " + getName() + " function!");
@@ -289,31 +393,62 @@ public class BoxFunction extends GeometryFunction {
 			throw new Exception("Impossible to replace an ADQLOperand by a " + replacer.getClass().getName() + " (" + replacer.toADQL() + ")!");
 
 		ADQLOperand replaced = null;
-		switch(index) {
-			case 0:
-				replaced = coordSys;
-				setCoordinateSystem(replacer);
-				break;
-			case 1:
-				replaced = coord1;
-				coord1 = replacer;
-				break;
-			case 2:
-				replaced = coord2;
-				coord2 = replacer;
-				break;
-			case 3:
-				replaced = width;
-				width = replacer;
-				break;
-			case 4:
-				replaced = height;
-				height = replacer;
-				break;
-			default:
-				throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!");
+		if (centerPoint == null) {
+			switch(index) {
+				case 0:
+					replaced = coordSys;
+					setCoordinateSystem(replacer);
+					break;
+				case 1:
+					replaced = coord1;
+					setCoord1(replacer);
+					break;
+				case 2:
+					replaced = coord2;
+					setCoord2(replacer);
+					break;
+				case 3:
+					replaced = width;
+					setWidth(replacer);
+					break;
+				case 4:
+					replaced = height;
+					setHeight(replacer);
+					break;
+				default:
+					throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!");
+			}
+		} else {
+			switch(index) {
+				case 0:
+					replaced = coordSys;
+					setCoordinateSystem(replacer);
+					break;
+				case 1:
+					replaced = centerPoint;
+					if (replacer instanceof GeometryValue)
+						setCenter((GeometryValue<GeometryFunction>)replacer);
+					else if (replaced instanceof ADQLColumn)
+						centerPoint.setColumn((ADQLColumn)replaced);
+					else if (replaced instanceof GeometryFunction)
+						centerPoint.setGeometry((GeometryFunction)replaced);
+					else if (replaced instanceof UserDefinedFunction)
+						centerPoint.setUDF((UserDefinedFunction)replaced);
+					else
+						throw new Exception("Impossible to replace a GeometryValue/Column/GeometryFunction/UDF by " + replacer.getClass().getName() + " (" + replacer.toADQL() + ")!");
+					break;
+				case 2:
+					replaced = width;
+					setWidth(replacer);
+					break;
+				case 3:
+					replaced = height;
+					setHeight(replacer);
+					break;
+				default:
+					throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!");
+			}
 		}
-		setPosition(null);
 		return replaced;
 	}
 
diff --git a/src/adql/query/operand/function/geometry/CircleFunction.java b/src/adql/query/operand/function/geometry/CircleFunction.java
index a03bb34bfd6d0f1a6b37c9630f56a9e943b4ce49..1f243dc375f9cbd9edd22fc8234d0b4dcc75d01d 100644
--- a/src/adql/query/operand/function/geometry/CircleFunction.java
+++ b/src/adql/query/operand/function/geometry/CircleFunction.java
@@ -16,13 +16,15 @@ package adql.query.operand.function.geometry;
  * You should have received a copy of the GNU Lesser General Public License
  * along with ADQLLibrary.  If not, see <http://www.gnu.org/licenses/>.
  *
- * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ * Copyright 2012-2020 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
 import adql.parser.feature.LanguageFeature;
 import adql.query.ADQLObject;
+import adql.query.operand.ADQLColumn;
 import adql.query.operand.ADQLOperand;
+import adql.query.operand.function.UserDefinedFunction;
 
 /**
  * It represents the CIRCLE function of the ADQL language.
@@ -57,7 +59,7 @@ import adql.query.operand.ADQLOperand;
  *
  * <p>
  * 	The position argument may be a literal value, as above, or it may be a
- * 	column reference, function or expression that returns a geometric type.
+ * 	column reference, function or expression that returns a POINT value.
  * </p>
  *
  * <i>
@@ -77,7 +79,7 @@ import adql.query.operand.ADQLOperand;
  * </p>
  *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.0 (07/2019)
+ * @version 2.0 (06/2020)
  */
 public class CircleFunction extends GeometryFunction {
 
@@ -85,10 +87,23 @@ public class CircleFunction extends GeometryFunction {
 	 * @since 2.0 */
 	public static final LanguageFeature FEATURE = new LanguageFeature(LanguageFeature.TYPE_ADQL_GEO, "CIRCLE", true, "Express a circular region on the sky (i.e. a cone in space).");
 
-	/** The first coordinate of the center position. */
+	/** Center position.
+	 * <p><i><b>Note:</b>
+	 * 	NULL, if both {@link #coord1} and {@link #coord2} are provided.
+	 * </i></p>
+	 * @since 2.0 */
+	private GeometryValue<GeometryFunction> centerPoint;
+
+	/** The first coordinate of the center position.
+	 * <p><i><b>Note:</b>
+	 * 	NULL, if {@link #centerPoint} is provided.
+	 * </i></p> */
 	private ADQLOperand coord1;
 
-	/** The second coordinate of the center position. */
+	/** The second coordinate of the center position.
+	 * <p><i><b>Note:</b>
+	 * 	NULL, if {@link #centerPoint} is provided.
+	 * </i></p> */
 	private ADQLOperand coord2;
 
 	/** The radius of the circle (in degrees). */
@@ -107,6 +122,7 @@ public class CircleFunction extends GeometryFunction {
 	 *                             	or if the coordinate system is unknown.
 	 * @throws Exception 			If there is another error.
 	 */
+	@SuppressWarnings("deprecation")
 	public CircleFunction(ADQLOperand coordinateSystem, ADQLOperand firstCoord, ADQLOperand secondCoord, ADQLOperand radius) throws NullPointerException, Exception {
 		super(coordinateSystem);
 
@@ -115,6 +131,33 @@ public class CircleFunction extends GeometryFunction {
 
 		coord1 = firstCoord;
 		coord2 = secondCoord;
+		centerPoint = null;
+		this.radius = radius;
+	}
+
+	/**
+	 * Builds a CIRCLE function.
+	 *
+	 * @param coordinateSystem		The coordinate system in which the center
+	 *                        		position is expressed.
+	 * @param center				The center position.
+	 * @param radius				The radius of the circle (in degrees).
+	 * @throws NullPointerException	If at least one parameter is incorrect
+	 *                             	or if the coordinate system is unknown.
+	 * @throws Exception 			If there is another error.
+	 *
+	 * @since 2.0
+	 */
+	@SuppressWarnings("deprecation")
+	public CircleFunction(ADQLOperand coordinateSystem, GeometryValue<GeometryFunction> center, ADQLOperand radius) throws NullPointerException, Exception {
+		super(coordinateSystem);
+
+		if (center == null || radius == null)
+			throw new NullPointerException("All parameters of a CIRCLE function must be different from NULL!");
+
+		coord1 = null;
+		coord2 = null;
+		centerPoint = center;
 		this.radius = radius;
 	}
 
@@ -124,10 +167,12 @@ public class CircleFunction extends GeometryFunction {
 	 * @param toCopy		The CIRCLE function to copy.
 	 * @throws Exception	If there is an error during the copy.
 	 */
+	@SuppressWarnings("unchecked")
 	public CircleFunction(CircleFunction toCopy) throws Exception {
 		super(toCopy);
 		coord1 = (ADQLOperand)(toCopy.coord1.getCopy());
 		coord2 = (ADQLOperand)(toCopy.coord2.getCopy());
+		centerPoint = (GeometryValue<GeometryFunction>)(toCopy.centerPoint.getCopy());
 		radius = (ADQLOperand)(toCopy.radius.getCopy());
 	}
 
@@ -161,6 +206,42 @@ public class CircleFunction extends GeometryFunction {
 		return true;
 	}
 
+	/**
+	 * Gets the center point, exactly as provided.
+	 *
+	 * <p><b>IMPORTANT NOTE:</b>
+	 * 	If this {@link CircleFunction} has been initialized with a pair of
+	 * 	coordinates, this function will return NULL.
+	 * </p>
+	 *
+	 * @return	The center point of the represented circle,
+	 *        	or NULL if created with a pair of coordinates.
+	 *
+	 * @since 2.0
+	 */
+	public final GeometryValue<GeometryFunction> getCenter() {
+		return centerPoint;
+	}
+
+	/**
+	 * Sets the center point.
+	 *
+	 * <p><b>WARNING:</b>
+	 * 	Calling this function will erase the single coordinates already set:
+	 * 	{@link #getCoord1()} and {@link #getCoord2()} will both return NULL.
+	 * </p>
+	 *
+	 * @param newCenter	The new center point of the represented circle.
+	 *
+	 * @since 2.0
+	 */
+	public final void setCenter(final GeometryValue<GeometryFunction> newCenter) {
+		centerPoint = newCenter;
+		coord1 = null;
+		coord2 = null;
+		setPosition(null);
+	}
+
 	/**
 	 * Gets the first coordinate of the center (i.e. right ascension).
 	 *
@@ -173,10 +254,16 @@ public class CircleFunction extends GeometryFunction {
 	/**
 	 * Sets the first coordinate of the center (i.e. right ascension).
 	 *
+	 * <p><b>WARNING:</b>
+	 * 	Calling this function will erase the center point already set:
+	 * 	{@link #getCenter()} will return NULL.
+	 * </p>
+	 *
 	 * @param coord1 The first coordinate.
 	 */
 	public final void setCoord1(ADQLOperand coord1) {
 		this.coord1 = coord1;
+		centerPoint = null;
 		setPosition(null);
 	}
 
@@ -196,6 +283,7 @@ public class CircleFunction extends GeometryFunction {
 	 */
 	public final void setCoord2(ADQLOperand coord2) {
 		this.coord2 = coord2;
+		centerPoint = null;
 		setPosition(null);
 	}
 
@@ -219,58 +307,104 @@ public class CircleFunction extends GeometryFunction {
 	}
 
 	@Override
+	@SuppressWarnings("deprecation")
 	public ADQLOperand[] getParameters() {
-		return new ADQLOperand[]{ coordSys, coord1, coord2, radius };
+		if (centerPoint == null)
+			return new ADQLOperand[]{ coordSys, coord1, coord2, radius };
+		else
+			return new ADQLOperand[]{ coordSys, centerPoint.getValue(), radius };
 	}
 
 	@Override
 	public int getNbParameters() {
-		return 4;
+		return (centerPoint == null ? 4 : 3);
 	}
 
 	@Override
+	@SuppressWarnings("deprecation")
 	public ADQLOperand getParameter(int index) throws ArrayIndexOutOfBoundsException {
-		switch(index) {
-			case 0:
-				return coordSys;
-			case 1:
-				return coord1;
-			case 2:
-				return coord2;
-			case 3:
-				return radius;
-			default:
-				throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!");
+		if (centerPoint == null) {
+			switch(index) {
+				case 0:
+					return coordSys;
+				case 1:
+					return coord1;
+				case 2:
+					return coord2;
+				case 3:
+					return radius;
+				default:
+					throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!");
+			}
+		} else {
+			switch(index) {
+				case 0:
+					return coordSys;
+				case 1:
+					return centerPoint.getValue();
+				case 2:
+					return radius;
+				default:
+					throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!");
+			}
 		}
 	}
 
 	@Override
+	@SuppressWarnings({ "unchecked", "deprecation" })
 	public ADQLOperand setParameter(int index, ADQLOperand replacer) throws ArrayIndexOutOfBoundsException, NullPointerException, Exception {
 		if (replacer == null)
 			throw new NullPointerException("Impossible to remove one parameter of a " + getName() + " function!");
 
 		ADQLOperand replaced = null;
-		switch(index) {
-			case 0:
-				replaced = coordSys;
-				setCoordinateSystem(replacer);
-				break;
-			case 1:
-				replaced = coord1;
-				coord1 = replacer;
-				break;
-			case 2:
-				replaced = coord2;
-				coord2 = replacer;
-				break;
-			case 3:
-				replaced = radius;
-				radius = replacer;
-				break;
-			default:
-				throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!");
+		if (centerPoint == null) {
+			switch(index) {
+				case 0:
+					replaced = coordSys;
+					setCoordinateSystem(replacer);
+					break;
+				case 1:
+					replaced = coord1;
+					setCoord1(replacer);
+					break;
+				case 2:
+					replaced = coord2;
+					setCoord2(replacer);
+					break;
+				case 3:
+					replaced = radius;
+					setRadius(replacer);
+					break;
+				default:
+					throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!");
+			}
+		} else {
+			switch(index) {
+				case 0:
+					replaced = coordSys;
+					setCoordinateSystem(replacer);
+					break;
+				case 1:
+					replaced = centerPoint.getValue();
+					if (replacer instanceof GeometryValue)
+						setCenter((GeometryValue<GeometryFunction>)replacer);
+					else if (replaced instanceof ADQLColumn)
+						centerPoint.setColumn((ADQLColumn)replaced);
+					else if (replaced instanceof GeometryFunction)
+						centerPoint.setGeometry((GeometryFunction)replaced);
+					else if (replaced instanceof UserDefinedFunction)
+						centerPoint.setUDF((UserDefinedFunction)replaced);
+					else
+						throw new Exception("Impossible to replace a GeometryValue/Column/GeometryFunction/UDF by " + replacer.getClass().getName() + " (" + replacer.toADQL() + ")!");
+					break;
+				case 2:
+					replaced = radius;
+					setRadius(replacer);
+					break;
+				default:
+					throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!");
+			}
 		}
-		setPosition(null);
 		return replaced;
 	}
 
diff --git a/src/adql/query/operand/function/geometry/DistanceFunction.java b/src/adql/query/operand/function/geometry/DistanceFunction.java
index 1065340831284fb9894d24b0c76d60bc875027cd..e1cc8e0e1ed83c84d80be011cd8a5a57447ee517 100644
--- a/src/adql/query/operand/function/geometry/DistanceFunction.java
+++ b/src/adql/query/operand/function/geometry/DistanceFunction.java
@@ -24,6 +24,7 @@ import adql.parser.feature.LanguageFeature;
 import adql.query.ADQLObject;
 import adql.query.operand.ADQLColumn;
 import adql.query.operand.ADQLOperand;
+import adql.query.operand.function.UserDefinedFunction;
 
 /**
  * It represents the DISTANCE function of the ADQL language.
@@ -231,9 +232,9 @@ public class DistanceFunction extends GeometryFunction {
 	public ADQLOperand getParameter(int index) throws ArrayIndexOutOfBoundsException {
 		switch(index) {
 			case 0:
-				return p1.getValue();
+				return p1;
 			case 1:
-				return p2.getValue();
+				return p2;
 			default:
 				throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!");
 		}
@@ -244,8 +245,8 @@ public class DistanceFunction extends GeometryFunction {
 	public ADQLOperand setParameter(int index, ADQLOperand replacer) throws ArrayIndexOutOfBoundsException, NullPointerException, Exception {
 		if (replacer == null)
 			throw new NullPointerException("Impossible to remove a parameter from the function " + getName() + "!");
-		else if (!(replacer instanceof GeometryValue || replacer instanceof ADQLColumn || replacer instanceof GeometryFunction))
-			throw new Exception("Impossible to replace a GeometryValue/Column/GeometryFunction by " + replacer.getClass().getName() + " (" + replacer.toADQL() + ")!");
+		else if (!(replacer instanceof GeometryValue || replacer instanceof ADQLColumn || replacer instanceof GeometryFunction || replacer instanceof UserDefinedFunction))
+			throw new Exception("Impossible to replace a GeometryValue/Column/GeometryFunction/UDF by " + replacer.getClass().getName() + " (" + replacer.toADQL() + ")!");
 
 		ADQLOperand replaced = null;
 		GeometryValue<GeometryFunction> toUpdate = null;
@@ -273,6 +274,8 @@ public class DistanceFunction extends GeometryFunction {
 				toUpdate.setColumn((ADQLColumn)replacer);
 			else if (replacer instanceof GeometryFunction)
 				toUpdate.setGeometry((GeometryFunction)replacer);
+			else if (replacer instanceof UserDefinedFunction)
+				toUpdate.setUDF((UserDefinedFunction)replacer);
 		}
 
 		setPosition(null);
diff --git a/src/adql/query/operand/function/geometry/GeometryFunction.java b/src/adql/query/operand/function/geometry/GeometryFunction.java
index 629cf85ae2af0313c89f53d24a7d836afa0bc98d..88ca95f2e2b479b98b20fa1ba73e63689b74b6b1 100644
--- a/src/adql/query/operand/function/geometry/GeometryFunction.java
+++ b/src/adql/query/operand/function/geometry/GeometryFunction.java
@@ -34,12 +34,21 @@ import adql.query.operand.function.UserDefinedFunction;
 /**
  * It represents any geometric function of ADQL.
  *
+ * <p>
+ * 	For historical reasons, the geometry regions accept an optional string value
+ * 	as the first argument. As of this version of the specification (2.1) this
+ * 	parameter has been marked as deprecated. Future versions of this
+ * 	specification (>2.1) may remove this parameter.
+ * </p>
+ *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 1.4 (06/2015)
+ * @version 2.0 (06/2020)
  */
 public abstract class GeometryFunction extends ADQLFunction {
 
-	/** The coordinate system used to express the coordinates. */
+	/** The coordinate system used to express the coordinates.
+	 * @deprecated Since ADQL-2.1. */
+	@Deprecated
 	protected ADQLOperand coordSys = null;
 
 	/**
@@ -61,7 +70,10 @@ public abstract class GeometryFunction extends ADQLFunction {
 	 * @throws NullPointerException				If the given operand is NULL.
 	 * @throws Exception						If the given operand is not a
 	 *                  						string.
+	 *
+	 * @deprecated Since ADQL-2.1, the coordinate system argument is deprecated.
 	 */
+	@Deprecated
 	protected GeometryFunction(ADQLOperand coordSys) throws UnsupportedOperationException, NullPointerException, Exception {
 		setCoordinateSystem(coordSys);
 	}
@@ -81,7 +93,10 @@ public abstract class GeometryFunction extends ADQLFunction {
 	 * Gets the used coordinate system.
 	 *
 	 * @return	Its coordinate system.
+	 *
+	 * @deprecated Since ADQL-2.1.
 	 */
+	@Deprecated
 	public ADQLOperand getCoordinateSystem() {
 		return coordSys;
 	}
@@ -96,7 +111,10 @@ public abstract class GeometryFunction extends ADQLFunction {
 	 * @throws NullPointerException				If the given operand is NULL.
 	 * @throws ParseException					If the given operand is not a
 	 *                       					string.
+	 *
+	 * @deprecated Since ADQL-2.1.
 	 */
+	@Deprecated
 	public void setCoordinateSystem(ADQLOperand coordSys) throws UnsupportedOperationException, NullPointerException, ParseException {
 		if (coordSys == null)
 			this.coordSys = new StringConstant("");
diff --git a/src/adql/query/operand/function/geometry/PointFunction.java b/src/adql/query/operand/function/geometry/PointFunction.java
index 7ea1a70167f76d9f9842177739ed4c4b3b14b6da..1a06a79326a588229ae09f20c4071237be59ccdc 100644
--- a/src/adql/query/operand/function/geometry/PointFunction.java
+++ b/src/adql/query/operand/function/geometry/PointFunction.java
@@ -71,7 +71,7 @@ import adql.query.operand.ADQLOperand;
  * </p>
  *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.0 (07/2019)
+ * @version 2.0 (06/2020)
  */
 public class PointFunction extends GeometryFunction {
 
@@ -98,6 +98,7 @@ public class PointFunction extends GeometryFunction {
 	 * @throws ParseException					If at least one of the given
 	 *                       					parameters is incorrect.
 	 */
+	@SuppressWarnings("deprecation")
 	public PointFunction(ADQLOperand coordinateSystem, ADQLOperand firstCoord, ADQLOperand secondCoord) throws UnsupportedOperationException, NullPointerException, Exception {
 		super(coordinateSystem);
 
@@ -204,6 +205,7 @@ public class PointFunction extends GeometryFunction {
 		return true;
 	}
 
+	@SuppressWarnings("deprecation")
 	@Override
 	public ADQLOperand[] getParameters() {
 		return new ADQLOperand[]{ coordSys, coord1, coord2 };
@@ -215,6 +217,7 @@ public class PointFunction extends GeometryFunction {
 	}
 
 	@Override
+	@SuppressWarnings("deprecation")
 	public ADQLOperand getParameter(int index) throws ArrayIndexOutOfBoundsException {
 		switch(index) {
 			case 0:
@@ -229,6 +232,7 @@ public class PointFunction extends GeometryFunction {
 	}
 
 	@Override
+	@SuppressWarnings("deprecation")
 	public ADQLOperand setParameter(int index, ADQLOperand replacer) throws ArrayIndexOutOfBoundsException, NullPointerException, Exception {
 		if (replacer == null)
 			throw new NullPointerException("Impossible to remove a parameter from the function " + getName() + "!");
diff --git a/src/adql/query/operand/function/geometry/PolygonFunction.java b/src/adql/query/operand/function/geometry/PolygonFunction.java
index 61fac169830526faf04a16347d110897ca8abc81..b9bc8eeb93cf85712a509147fd43eb55ce300a4d 100644
--- a/src/adql/query/operand/function/geometry/PolygonFunction.java
+++ b/src/adql/query/operand/function/geometry/PolygonFunction.java
@@ -16,11 +16,12 @@ package adql.query.operand.function.geometry;
  * You should have received a copy of the GNU Lesser General Public License
  * along with ADQLLibrary.  If not, see <http://www.gnu.org/licenses/>.
  *
- * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ * Copyright 2012-2020 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.Vector;
 
 import adql.parser.feature.LanguageFeature;
@@ -32,7 +33,7 @@ import adql.query.operand.ADQLOperand;
  *
  * <p>
  * 	This function expresses a region on the sky with boundaries denoted by great
- * 	circles passing through specified coordinates. It corresponds semantically
+ * 	circles passing through specified vertices. It corresponds semantically
  * 	to the STC Polygon.
  * </p>
  *
@@ -58,6 +59,8 @@ import adql.query.operand.ADQLOperand;
  * </p>
  * <pre>POLYGON(10.0, -10.5, 20.0, 20.5, 30.0, 30.5)</pre>
  * <p>, where all numeric values are in degrees.</p>
+ * <p>or alternatively as follows:</p>
+ * <pre>POLYGON(POINT(10.0, -10.5), POINT(20.0, 20.5), POINT(30.0, 30.5))</pre>
  * </i>
  *
  * <p>
@@ -103,7 +106,7 @@ import adql.query.operand.ADQLOperand;
  * </p>
  *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.0 (07/2019)
+ * @version 2.0 (06/2020)
  */
 public class PolygonFunction extends GeometryFunction {
 
@@ -111,7 +114,7 @@ public class PolygonFunction extends GeometryFunction {
 	 * @since 2.0 */
 	public static final LanguageFeature FEATURE = new LanguageFeature(LanguageFeature.TYPE_ADQL_GEO, "POLYGON", true, "Express a region on the sky with boundaries denoted by great circles passing through specified coordinates.");
 
-	/** The coordinates of vertices. */
+	/** The vertices. */
 	protected Vector<ADQLOperand> coordinates;
 
 	/**
@@ -131,6 +134,7 @@ public class PolygonFunction extends GeometryFunction {
 	 *                             				NULL.
 	 * @throws Exception						If there is another error.
 	 */
+	@SuppressWarnings("deprecation")
 	public PolygonFunction(ADQLOperand coordSystem, ADQLOperand[] coords) throws UnsupportedOperationException, NullPointerException, Exception {
 		super(coordSystem);
 		if (coords == null || coords.length < 6)
@@ -143,14 +147,18 @@ public class PolygonFunction extends GeometryFunction {
 	}
 
 	/**
-	 * Builds a polygon function with at least 3 2-D coordinates (that is to
-	 * say, the vector must contain at least 6 operands).
+	 * Builds a polygon function with at least:
+	 *
+	 * <ul>
+	 * 	<li>3 pairs of coordinates (that is to say, the vector must contain at
+	 * 		least 6 items),</li>
+	 * 	<li>OR 3 point values (so, a vector containing at least 3 items).</li>
+	 * </ul>
 	 *
 	 * @param coordSystem						A string operand which
 	 *                   						corresponds to a valid
 	 *                   						coordinate system.
-	 * @param coords							A vector of at least 3 2-D
-	 *              							coordinates (size()>=6).
+	 * @param coords							A vector of at least 3 vertices.
 	 *
 	 * @throws UnsupportedOperationException	If this function is not
 	 *                                      	associated with a coordinate
@@ -159,10 +167,16 @@ public class PolygonFunction extends GeometryFunction {
 	 *                             				NULL.
 	 * @throws Exception						If there is another error.
 	 */
+	@SuppressWarnings("deprecation")
 	public PolygonFunction(ADQLOperand coordSystem, Collection<? extends ADQLOperand> coords) throws UnsupportedOperationException, NullPointerException, Exception {
 		super(coordSystem);
-		if (coords == null || coords.size() < 6)
-			throw new NullPointerException("A POLYGON function must have at least 3 2-D coordinates!");
+		if (coords == null)
+			throw new NullPointerException("A POLYGON function must have vertices!");
+
+		Iterator<?> itCoords = coords.iterator();
+		Object firstItem = (itCoords.hasNext() ? itCoords.next() : null);
+		if (firstItem == null || (firstItem instanceof GeometryValue<?> && coords.size() < 3) || (!(firstItem instanceof GeometryValue<?>) && coords.size() < 6))
+			throw new NullPointerException("A POLYGON function must have at least 3 vertices (i.e. 3 points or 3 pairs of coordinates)!");
 		else {
 			coordinates = new Vector<ADQLOperand>(coords.size());
 			coordinates.addAll(coords);
@@ -213,6 +227,7 @@ public class PolygonFunction extends GeometryFunction {
 	}
 
 	@Override
+	@SuppressWarnings("deprecation")
 	public ADQLOperand[] getParameters() {
 		ADQLOperand[] params = new ADQLOperand[coordinates.size() + 1];
 
@@ -229,6 +244,7 @@ public class PolygonFunction extends GeometryFunction {
 	}
 
 	@Override
+	@SuppressWarnings("deprecation")
 	public ADQLOperand getParameter(int index) throws ArrayIndexOutOfBoundsException {
 		if (index == 0)
 			return coordSys;
@@ -239,6 +255,7 @@ public class PolygonFunction extends GeometryFunction {
 	}
 
 	@Override
+	@SuppressWarnings("deprecation")
 	public ADQLOperand setParameter(int index, ADQLOperand replacer) throws ArrayIndexOutOfBoundsException, NullPointerException, Exception {
 		if (replacer == null)
 			throw new NullPointerException("Impossible to remove only one parameter from the function POLYGON!");
diff --git a/src/adql/translator/PgSphereTranslator.java b/src/adql/translator/PgSphereTranslator.java
index 360b57c2fa67c9547d08c2399a45406839e3bf0c..ea09378fccccd2c9b4092db54e52f9c83b12b3b5 100644
--- a/src/adql/translator/PgSphereTranslator.java
+++ b/src/adql/translator/PgSphereTranslator.java
@@ -16,7 +16,7 @@ package adql.translator;
  * You should have received a copy of the GNU Lesser General Public License
  * along with ADQLLibrary.  If not, see <http://www.gnu.org/licenses/>.
  *
- * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
+ * Copyright 2012-2020 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
  *                       Astronomisches Rechen Institut (ARI)
  */
 
@@ -62,7 +62,7 @@ import adql.query.operand.function.geometry.PolygonFunction;
  * </i></p>
  *
  * @author Gr&eacute;gory Mantelet (CDS;ARI)
- * @version 2.0 (08/2019)
+ * @version 2.0 (06/2020)
  */
 public class PgSphereTranslator extends PostgreSQLTranslator {
 
@@ -243,17 +243,17 @@ public class PgSphereTranslator extends PostgreSQLTranslator {
 			}
 			try {
 				// build the CIRCLE to use in the artificial CONTAINS:
-				CircleFunction circleFct = new CircleFunction(new StringConstant(""), ((PointFunction)distFct.getParameter(1)).getCoord1(), ((PointFunction)distFct.getParameter(1)).getCoord2(), numericOperand);
+				CircleFunction circleFct = new CircleFunction(new StringConstant(""), ((PointFunction)distFct.getP2().getValue()).getCoord1(), ((PointFunction)distFct.getP2().getValue()).getCoord2(), numericOperand);
 				// adapt the translation in function of the comp. operator:
 				switch(comp.getOperator()) {
 					case LESS_THAN:
-						return "((" + translate(distFct.getParameter(0)) + " @ " + translate(circleFct) + ") = '1' AND " + super.translate(comp) + ")";
+						return "((" + translate(distFct.getP1()) + " @ " + translate(circleFct) + ") = '1' AND " + super.translate(comp) + ")";
 					case LESS_OR_EQUAL:
-						return "((" + translate(distFct.getParameter(0)) + " @ " + translate(circleFct) + ") = '1'" + ")";
+						return "((" + translate(distFct.getP1()) + " @ " + translate(circleFct) + ") = '1'" + ")";
 					case GREATER_THAN:
-						return "((" + translate(distFct.getParameter(0)) + " @ " + translate(circleFct) + ") = '0' AND " + super.translate(comp) + ")";
+						return "((" + translate(distFct.getP1()) + " @ " + translate(circleFct) + ") = '0' AND " + super.translate(comp) + ")";
 					case GREATER_OR_EQUAL:
-						return "((" + translate(distFct.getParameter(0)) + " @ " + translate(circleFct) + ") = '0'" + ")";
+						return "((" + translate(distFct.getP1()) + " @ " + translate(circleFct) + ") = '0'" + ")";
 					default: // theoretically, this case never happens!
 						return super.translate(comp);
 				}
diff --git a/test/adql/parser/TestADQLParser.java b/test/adql/parser/TestADQLParser.java
index 2a449963c626b14649029aaf1ae497ea4daa5d58..b6883386b203d8681111d0bb07338f415c38519e 100644
--- a/test/adql/parser/TestADQLParser.java
+++ b/test/adql/parser/TestADQLParser.java
@@ -870,10 +870,12 @@ public class TestADQLParser {
 	}
 
 	@Test
-	public void testGeometryWithNoCooSys() {
+	public void testGeometryWithOptionalArgs() {
 		/*
 		 * NOTE:
 		 * 	Since ADQL-2.1, the coordinate system argument becomes optional.
+		 *  Besides, BOX, CIRCLE and POLYGON can now accept POINTs instead of
+		 *  pairs of coordinates.
 		 */
 
 		ADQLParser parser = new ADQLParser(ADQLVersion.V2_1);
@@ -881,21 +883,32 @@ public class TestADQLParser {
 		// CASE: with no coordinate system => equivalent to coosys = ''
 		try {
 			assertEquals("POINT('', 1, 2)", parser.parseSelect("SELECT POINT(1, 2)").get(0).toADQL());
+
 			assertEquals("CIRCLE('', 1, 2, 3)", parser.parseSelect("SELECT CIRCLE(1, 2, 3)").get(0).toADQL());
+			assertEquals("CIRCLE('', POINT('', 1, 2), 3)", parser.parseSelect("SELECT CIRCLE(POINT(1,2), 3)").get(0).toADQL());
+			assertEquals("CIRCLE('', colCenter, 3)", parser.parseSelect("SELECT CIRCLE(colCenter, 3)").get(0).toADQL());
+
 			assertEquals("BOX('', 1, 2, 3, 4)", parser.parseSelect("SELECT BOX(1, 2, 3, 4)").get(0).toADQL());
+			assertEquals("BOX('', POINT('', 1, 2), 3, 4)", parser.parseSelect("SELECT BOX(POINT(1, 2), 3, 4)").get(0).toADQL());
+			assertEquals("BOX('', colCenter, 3, 4)", parser.parseSelect("SELECT BOX(colCenter, 3, 4)").get(0).toADQL());
+
 			assertEquals("POLYGON('', 1, 2, 3, 4, 5, 6)", parser.parseSelect("SELECT POLYGON(1, 2, 3, 4, 5, 6)").get(0).toADQL());
+			assertEquals("POLYGON('', POINT('', 1, 2), POINT('', 3, 4), POINT('', 5, 6))", parser.parseSelect("SELECT POLYGON(POINT(1, 2), POINT(3, 4), POINT(5, 6))").get(0).toADQL());
+			assertEquals("POLYGON('', point1, point2, point3)", parser.parseSelect("SELECT POLYGON(point1, point2, point3)").get(0).toADQL());
 		} catch(Exception ex) {
 			ex.printStackTrace();
 			fail("Unexpected error! All parsed geometries are correct.");
 		}
 
-		// CASE: ambiguity with POLYGON and a wrong nb of arguments
-		try {
-			assertEquals("POLYGON(ra, dec, 3, 4, 5, 6, 7)", parser.parseSelect("SELECT POLYGON(ra, dec, 3, 4, 5, 6, 7)").get(0).toADQL());
-		} catch(Exception ex) {
-			ex.printStackTrace();
-			fail("Unexpected error! All parsed geometries are \"correct\".");
-		}
+		// CASE: wrong nb of arguments for POLYGON
+		for(String wrongQuery : new String[]{ "SELECT POLYGON(ra, dec, 3, 4, 5)", "SELECT POLYGON(ra, dec, 3, 4, 5, 6, 7)", "SELECT POLYGON(p1, p2)" })
+			try {
+				parser.parseSelect(wrongQuery);
+				fail("Impossible to create a POLYGON with an incomplete list of vertices! The last point is missing or incomplete.");
+			} catch(Exception ex) {
+				assertEquals(ParseException.class, ex.getClass());
+				assertTrue(ex.getMessage().trim().startsWith("Encountered \")\"."));
+			}
 	}
 
 	@Test
@@ -904,6 +917,22 @@ public class TestADQLParser {
 			// DECLARE A SIMPLE PARSER where all coordinate systems are allowed by default:
 			ADQLParser parser = new ADQLParser(version);
 
+			// A coordinate system MUST be a string literal:
+			try {
+				assertNotNull(parser.parseQuery("SELECT * FROM foo WHERE CONTAINS(POINT('From ' || 'here', 12.3, 45.6), CIRCLE('', 1.2, 2.3, 5)) = 1;"));
+				fail("A coordinate system can NOT be a string concatenation!");
+			} catch(ParseException pe) {
+				assertEquals(ParseException.class, pe.getClass());
+				assertEquals(48, pe.getPosition().beginColumn);
+			}
+			try {
+				assertNotNull(parser.parseQuery("SELECT * FROM foo WHERE CONTAINS(POINT(aColumn, 12.3, 45.6), CIRCLE('', 1.2, 2.3, 5)) = 1;"));
+				fail("A coordinate system can NOT be a column reference!");
+			} catch(ParseException pe) {
+				assertEquals(ParseException.class, pe.getClass());
+				assertEquals((version == ADQLVersion.V2_0 ? 40 : 53), pe.getPosition().beginColumn);
+			}
+
 			// Test with several coordinate systems while all are allowed:
 			try {
 				assertNotNull(parser.parseQuery("SELECT * FROM foo WHERE CONTAINS(POINT('', 12.3, 45.6), CIRCLE('', 1.2, 2.3, 5)) = 1;"));
@@ -919,14 +948,6 @@ public class TestADQLParser {
 				fail("This query contains several valid coordinate systems, and all are theoretically allowed: this test should have succeeded!");
 			}
 
-			// Concatenation as coordinate systems not checked:
-			try {
-				assertNotNull(parser.parseQuery("SELECT * FROM foo WHERE CONTAINS(POINT('From ' || 'here', 12.3, 45.6), CIRCLE('', 1.2, 2.3, 5)) = 1;"));
-			} catch(ParseException pe) {
-				pe.printStackTrace();
-				fail("This query contains a concatenation as coordinate systems (but only string constants are checked): this test should have succeeded!");
-			}
-
 			// Test with several coordinate systems while only some allowed:
 			try {
 				parser = new ADQLParser(version);