diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..3d47f986c41db29ec6dc0d5036bf760b3a1cf366
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+.idea/
+target/
+.settings/
+*.iml
+.project
+.classpath
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9ab8c4ab02e1ed9a813eb595e08c6754924ebb8e
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <!-- Inherited Icy Parent POM -->
+    <parent>
+        <groupId>org.bioimageanalysis.icy</groupId>
+        <artifactId>parent-pom-plugin</artifactId>
+        <version>1.0.3</version>
+    </parent>
+
+    <!-- Project Information -->
+    <artifactId>angle-helper</artifactId>
+    <version>1.1.0</version>
+
+    <packaging>jar</packaging>
+
+    <name>Angle Helper</name>
+    <description>This repo serves as a template for you to implement new Icy plugins.</description>
+    <url>http://icy.bioimageanalysis.org/plugin/angle-helper/</url>
+    <inceptionYear>2020</inceptionYear>
+
+    <organization>
+        <name>Institut Pasteur</name>
+        <url>https://pasteur.fr</url>
+    </organization>
+
+    <licenses>
+        <license>
+            <name>GNU GPLv3</name>
+            <url>https://www.gnu.org/licenses/gpl-3.0.en.html</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+
+    <developers>
+        <developer>
+            <id>sdallongeville</id>
+            <name>Stéphane Dallongeville</name>
+            <url>https://research.pasteur.fr/fr/member/stephane-dallongeville/</url>
+            <roles>
+                <role>founder</role>
+                <role>lead</role>
+                <role>architect</role>
+                <role>developer</role>
+                <role>debugger</role>
+                <role>tester</role>
+                <role>maintainer</role>
+                <role>support</role>
+            </roles>
+        </developer>
+    </developers>
+
+    <!-- Project properties -->
+    <properties>
+
+    </properties>
+
+    <!-- Project build configuration -->
+    <build>
+
+    </build>
+
+    <!-- List of project's dependencies -->
+    <dependencies>
+        <!-- The core of Icy -->
+        <dependency>
+            <groupId>org.bioimageanalysis.icy</groupId>
+            <artifactId>icy-kernel</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.bioimageanalysis.icy</groupId>
+            <artifactId>xuggler</artifactId>
+            <version>5.5.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.bioimageanalysis.icy</groupId>
+            <artifactId>ruler-helper</artifactId>
+            <version>1.2.1</version>
+        </dependency>
+    </dependencies>
+
+    <!-- Icy Maven repository (to find parent POM) -->
+    <repositories>
+        <repository>
+            <id>icy</id>
+            <name>Icy's Nexus</name>
+            <url>https://icy-nexus.pasteur.fr/repository/Icy/</url>
+        </repository>
+    </repositories>
+</project>
diff --git a/src/main/java/plugins/fab/anglehelper/AngleHelper.java b/src/main/java/plugins/fab/anglehelper/AngleHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..58f19050f4d66183e261b9b8aff033b5a71653db
--- /dev/null
+++ b/src/main/java/plugins/fab/anglehelper/AngleHelper.java
@@ -0,0 +1,28 @@
+package plugins.fab.anglehelper;
+
+import icy.gui.dialog.MessageDialog;
+import icy.plugin.abstract_.Plugin;
+import icy.plugin.interface_.PluginImageAnalysis;
+import icy.sequence.Sequence;
+
+/**
+ * @author Fabrice de Chaumont
+ */
+public class AngleHelper extends Plugin implements PluginImageAnalysis {
+
+	@Override
+	public void compute() {
+
+		Sequence sequence = getFocusedSequence();
+		
+		if ( sequence!=null )
+		{
+			new AnglePainter( getFocusedSequence() );
+		}else
+		{
+			MessageDialog.showDialog("Please open an image first.", MessageDialog.INFORMATION_MESSAGE );
+		}
+		
+	}
+
+}
diff --git a/src/main/java/plugins/fab/anglehelper/AnglePainter.java b/src/main/java/plugins/fab/anglehelper/AnglePainter.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6714ed2ae3a5979369700e5d96d76fddf8aac36
--- /dev/null
+++ b/src/main/java/plugins/fab/anglehelper/AnglePainter.java
@@ -0,0 +1,336 @@
+package plugins.fab.anglehelper;
+
+import icy.canvas.IcyCanvas;
+import icy.canvas.IcyCanvas2D;
+import icy.gui.util.GuiUtil;
+import icy.main.Icy;
+import icy.math.Scaler;
+import icy.painter.Anchor2D;
+import icy.painter.Anchor2D.Anchor2DListener;
+import icy.painter.Painter;
+import icy.painter.PainterEvent;
+import icy.roi.ROI2D;
+import icy.sequence.Sequence;
+
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+
+import plugins.fab.Ruler.Anchor2DTarget;
+import plugins.fab.Ruler.ShapeDefinition;
+
+/**
+ * @author Fabrice de Chaumont
+ */
+public class AnglePainter implements Painter, Anchor2DListener {
+
+	Anchor2DTarget a1 = new Anchor2DTarget( 0 , 0 );
+	Anchor2DTarget a2 = new Anchor2DTarget( 0 , 0 );
+	Anchor2DTarget a3 = new Anchor2DTarget( 0 , 0 );
+	
+	ArrayList<ShapeDefinition> shapeDefinitionList = new ArrayList<ShapeDefinition>();
+	ArrayList<AffineTransform> affineTransformList = new ArrayList<AffineTransform>();
+	
+	public AnglePainter(Sequence sequence) {
+	
+		if ( sequence == null ) return;
+		
+		a1.setPosition( sequence.getWidth() / 2 , sequence.getHeight() / 2 );
+		a2.setPosition( 3 * sequence.getWidth() / 4 , sequence.getHeight() / 2 );
+		a3.setPosition( 3 * sequence.getWidth() / 4 , sequence.getHeight() / 3 );
+
+		sequence.addPainter( this );
+		a1.addListener( this );
+		a2.addListener( this );
+		a3.addListener( this );
+		
+	}
+	
+	// Listener of Anchor
+	
+	@Override
+	public void painterChanged(PainterEvent event) {
+		
+		for ( Sequence sequence : Icy.getMainInterface().getSequencesContaining( this ) )
+		{
+			sequence.painterChanged( this );
+		}
+		
+	}
+
+	@Override
+	public void positionChanged(Anchor2D source) {
+		
+		
+	}
+	
+	void pushTransform( Graphics2D g )
+	{
+		affineTransformList.add( g.getTransform() );
+	}
+
+	void popTransform( Graphics2D g )
+	{
+		g.setTransform( affineTransformList.get( affineTransformList.size() -1 ) );
+		affineTransformList.remove( affineTransformList.size() -1 );
+	}
+	
+	public double CleanAngle( double angle )
+	{
+		double a = Math.abs( angle );
+		a = Math.round(a*10)/10.;
+		return a;
+	}
+	
+	// Painter Section:
+
+	@Override
+	public void paint(Graphics2D g, Sequence sequence, IcyCanvas canvas) {
+		
+		if ( ! ( canvas instanceof IcyCanvas2D ) ) return;
+		
+		g= (Graphics2D) g.create();
+		
+		BasicStroke[] stroke = new BasicStroke[4];
+		
+		stroke[0] = new BasicStroke((float) ROI2D.canvasToImageLogDeltaX(canvas, 2 ) ); 
+		stroke[1] = new BasicStroke((float) ROI2D.canvasToImageLogDeltaX(canvas, 3 ) ); 
+		stroke[2] = new BasicStroke((float) ROI2D.canvasToImageLogDeltaX(canvas, 4 ) ); 
+		stroke[3] = new BasicStroke((float) ROI2D.canvasToImageLogDeltaX(canvas, 5 ) ); 
+				
+		// transform and display ticks
+
+		shapeDefinitionList.clear();
+	
+		pushTransform( g );
+		
+		double vx12 = ( a2.getX() - a1.getX() ) ;
+		double vy12 = ( a2.getY() - a1.getY() ) ;
+		double angle12 = Math.atan2( vy12 , vx12 ) * ( 180d / Math.PI ) ;
+
+		double vx13 = ( a3.getX() - a1.getX() ) ;
+		double vy13 = ( a3.getY() - a1.getY() ) ;
+		double angle13 = Math.atan2( vy13 , vx13 ) * ( 180d / Math.PI );
+
+		double angle1 = angle12-angle13;
+
+		if ( angle1 < 0 ) angle1+=360;
+		
+		double angle2 = 360-angle1;
+		
+		double dis1 = a1.getPosition().distance( a2.getPosition() );
+		double dis2 = a1.getPosition().distance( a3.getPosition() );
+		
+		double minDistance = Math.min( dis1 , dis2 );		
+
+		double distanceAngle1 = minDistance ;
+		double distanceAngle2 = minDistance / 2;
+
+		double distanceTextAngle1 = minDistance;
+		double distanceTextAngle2 = minDistance/2;
+		
+		// Lines
+		
+		shapeDefinitionList.add( new ShapeDefinition( 2 , new Line2D.Double( a1.getPosition() , a2.getPosition() ) ) );
+		shapeDefinitionList.add( new ShapeDefinition( 2 , new Line2D.Double( a1.getPosition() , a3.getPosition() ) ) );
+
+		// angle 1
+		{
+			double arcSize = distanceAngle1;
+			Arc2D arc = new Arc2D.Double( 
+					a1.getX() - arcSize/2d,
+					a1.getY() - arcSize/2d,
+					arcSize,
+					arcSize,
+					-angle12 ,
+					angle1,//angle13,
+					Arc2D.OPEN
+					);
+
+			shapeDefinitionList.add( new ShapeDefinition( 2 , arc ) );
+		}
+		
+		// angle 2
+		{
+			double arcSize = distanceAngle2;
+			Arc2D arc = new Arc2D.Double( 
+					a1.getX() - arcSize/2d,
+					a1.getY() - arcSize/2d,
+					arcSize,
+					arcSize,
+					-angle13 ,
+					angle2,//angle13,
+					Arc2D.OPEN
+					);
+
+			shapeDefinitionList.add( new ShapeDefinition( 2 , arc ) );
+		}
+
+		// draw lines ( black background, then white )
+		
+		float oldAlpha= -1;
+		g.setColor( Color.black );
+		for ( ShapeDefinition ld : shapeDefinitionList )
+		{
+			if (oldAlpha!=ld.alpha)
+			{
+				g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, ld.alpha ) );
+				oldAlpha = ld.alpha;
+			}
+			g.setStroke( stroke[ld.stroke] );
+			g.draw( ld.shape );
+		}
+
+		g.setColor( Color.white );
+		for ( ShapeDefinition ld : shapeDefinitionList )
+		{
+			if (oldAlpha!=ld.alpha)
+			{
+				g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, ld.alpha ) );
+				oldAlpha = ld.alpha;
+			}
+			g.setStroke( stroke[ld.stroke-1] );
+			g.draw( ld.shape );
+		}
+		
+		// Display angle text
+		
+		{
+			int fontSize =  (int)convertScale(canvas, 15 );
+			Font font =  new Font( "Arial" , Font.PLAIN , fontSize ); 
+
+			pushTransform( g );
+			String pixelString = " "+ (int)( Math.round( angle1 ) ) + "° ";
+			Rectangle2D pixelBounds = GuiUtil.getStringBounds( g , font, pixelString );
+			g.translate( a1.getX() , a1.getY() );
+			
+			double angleText = Math.toRadians( angle12 - angle1 / 2d );			
+			g.translate( Math.cos( angleText  ) * distanceTextAngle1 /2 , Math.sin( angleText ) * distanceTextAngle1 /2 );
+			g.translate( -pixelBounds.getWidth() / 2 , 0 );
+			
+			g.setFont( font );
+			g.setColor( Color.white );
+			g.fill( pixelBounds );
+			g.setColor( Color.black );
+			g.drawString( pixelString , 0, 0 );
+			popTransform( g );
+		}
+
+		{
+			int fontSize =  (int)convertScale(canvas, 15 );
+			Font font =  new Font( "Arial" , Font.PLAIN , fontSize ); 
+
+			pushTransform( g );
+			String pixelString = " "+ (int)(Math.round( angle2 ) ) + "� ";
+			Rectangle2D pixelBounds = GuiUtil.getStringBounds( g , font, pixelString );
+			g.translate( a1.getX() , a1.getY() );
+			
+			double angleText = Math.toRadians( 180 + angle12 - angle1 / 2d );			
+			g.translate( Math.cos( angleText  ) * distanceTextAngle2 / 2d , Math.sin( angleText ) * distanceTextAngle2 / 2d );
+			g.translate( -pixelBounds.getWidth() / 2 , 0 );
+
+			float alpha = 1 ;
+			double distance = canvas.getScaleX() * distanceTextAngle2 / 2d ;
+			
+			Scaler scaler = new Scaler( 0 , 10 , 0, 1 , false );
+			alpha = (float)scaler.scale( distance - pixelBounds.getWidth() / 10d );
+					
+			g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha ) );
+
+			g.setFont( font );
+			g.setColor( Color.white );
+			g.fill( pixelBounds );
+			g.setColor( Color.black );
+			g.drawString( pixelString , 0, 0 );
+			
+			g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1 ) );
+			popTransform( g );
+		}
+		
+		// get back to original transform
+				
+		popTransform( g );
+
+		// display anchors
+		g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1 ) );
+		a1.paint( g, sequence, canvas);
+		a2.paint( g, sequence, canvas);
+		a3.paint( g, sequence, canvas);
+	}
+		
+	double convertScale( IcyCanvas canvas , double value )
+	{
+		return ROI2D.canvasToImageLogDeltaX(canvas, value ); 
+	}
+
+	@Override
+	public void mousePressed(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) {
+		a1.mousePressed(e, imagePoint, canvas);		
+		a2.mousePressed(e, imagePoint, canvas);
+		a3.mousePressed(e, imagePoint, canvas);
+	}
+
+	@Override
+	public void mouseReleased(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) {
+		a1.mouseReleased(e, imagePoint, canvas);
+		a2.mouseReleased(e, imagePoint, canvas);
+		a3.mouseReleased(e, imagePoint, canvas);
+	}
+
+	@Override
+	public void mouseClick(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) {
+		a1.mouseClick(e, imagePoint, canvas);
+		a2.mouseClick(e, imagePoint, canvas);
+		a3.mouseClick(e, imagePoint, canvas);
+		
+	}
+
+	@Override
+	public void mouseMove(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) {
+		a1.mouseMove(e, imagePoint, canvas);
+		a2.mouseMove(e, imagePoint, canvas);
+		a3.mouseMove(e, imagePoint, canvas);
+	}
+
+	@Override
+	public void mouseDrag(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) {
+		a1.mouseDrag(e, imagePoint, canvas);
+		a2.mouseDrag(e, imagePoint, canvas);
+		a3.mouseDrag(e, imagePoint, canvas);
+	}
+
+	@Override
+	public void keyPressed(KeyEvent e, Point2D imagePoint, IcyCanvas canvas) {
+				
+		if ( ( e.getKeyCode() == KeyEvent.VK_DELETE && a1.isSelected() ) || ( e.getKeyCode() == KeyEvent.VK_DELETE && a2.isSelected() ) )
+		{			
+			for ( Sequence sequence : Icy.getMainInterface().getSequencesContaining( this ) )
+			{
+				sequence.removePainter( this );
+			}
+			
+		}
+			
+		a1.keyPressed(e, imagePoint, canvas);
+		a2.keyPressed(e, imagePoint, canvas);
+		a3.keyPressed(e, imagePoint, canvas);
+	}
+
+	@Override
+	public void keyReleased(KeyEvent e, Point2D imagePoint, IcyCanvas canvas) {
+		a1.keyReleased(e, imagePoint, canvas);
+		a2.keyReleased(e, imagePoint, canvas);
+		a3.keyReleased(e, imagePoint, canvas);
+	}	
+	
+}