title: How to calculate the angle of lines drawn in flutter? Need to find the angle between two lines
body: <p>I'm working on a paint like application where lines and shapes can be drawn using tapped coordinates. I need to get the angle or degree of the lines drawn in my canvas. Have used CustomPaint to draw the lines and XGestureDetector to get the coordinates onTap.</p>
  <p><a href="https://i.stack.imgur.com/jGGG2.gif" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/jGGG2.gif" alt="enter image description here" /></a></p>
  <p>I Need to achieve the above.</p>
  <p>Here's my code,</p>
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>class LandingScreen extends State&lt;MyApp&gt; {
    LandingScreen(List&lt;List&lt;Offset&gt;&gt; connectionList);
  
    @override
    void initState() {
      XGesture();
      super.initState();
    }
  
    @override
    Widget build(BuildContext context) {
      late List&lt;List&lt;Offset&gt;&gt; _connectionList;
      _connectionList = [[Offset(104.0, 242.6), Offset(101.4, 559.3)], [Offset(238.9, 238.6), Offset(229.8, 440.4)]];
  
      String dropdownvalue = 'Square';
      var items = ['Square', ' Circle ', ' Rectangle ', ' Circle ',];
  
      return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Scaffold(
          body:
          XGesture(),
        ),
      );
    }
  }
  
  class XGesture extends StatefulWidget {
    late List&lt;List&lt;Offset&gt;&gt; connectionListRedo = [];
  
    @override
    _XGestureState createState() =&gt; _XGestureState();
  }
  
  class _XGestureState extends State&lt;XGesture&gt; {
    late MoveEvent pos1;
    late MoveEvent pos2;
    late List&lt;List&lt;Offset&gt;&gt; _connectionList;
    late List&lt;List&lt;Offset&gt;&gt; connectionListRedo1;
  
    _XGestureState();
  
    @override
    void initState() {
      onMoveStart;
      pos1 = MoveEvent(Offset(0.0, 0.0), Offset(0.0, 0.0), 0);
      pos2 = MoveEvent(Offset(0.0, 0.0), Offset(0.0, 0.0), 0);
      _connectionList = [];
      onMoveEnd;
      LandingScreen(_connectionList);
      super.initState();
    }
  
    @override
    Widget build(BuildContext context) {
      String dropdownvalue = 'Square';
      var items = [
        'Square',
        ' Circle ',
        ' Rectangle ',
        ' Circle ',
      ];
      String dropdownvalue1 = 'Teams';
      var items1 = [
        'Teams',
        ' Sluggers ',
        ' Lakes ',
        ' Add More ',
      ];
  
      final x = Angle.degrees(180.0);
      debugPrint('Angle of x : ${x.degrees}');
  
      return XGestureDetector(
        child: Material(
          color: Colors.black87,
          child: Center(
              child: CustomPaint(
            painter: LinePainter(pos1.localPos, pos2.localPos, _connectionList),
            child:SingleChildScrollView(
              scrollDirection: Axis.horizontal,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.start,
                children: &lt;Widget&gt;[
                  Align(
                    alignment: FractionalOffset.bottomLeft,
                    child:
                  Container(
                    padding: EdgeInsets.only(top: 0.5,bottom: 0.5,left: 0.0,right: 0.0),
                    decoration:BoxDecoration(
                        borderRadius:BorderRadius.circular(5),
                      border: Border.all(color: Colors.green, width: 4),
                      color: Color(0xDC063280),
                    ),
                    child: TextButton.icon(
                        label: const Text('Undo', textAlign: TextAlign.justify, style: TextStyle(fontSize: 20, color: Colors.white),),
                        icon: Icon(Icons.undo, color: Colors.white,),
                        onPressed: () {
                          widget.connectionListRedo.add(_connectionList.last);
                          debugPrint('Not Removed Offset List value: ${widget.connectionListRedo}');
                          _connectionList.removeLast();
                          debugPrint('Removed Offset List value: $_connectionList');
                          print('Pressed Undo btn');
                        }),
                  ),
          ),
                  Align(
                    alignment: FractionalOffset.bottomLeft,
                    child:
                    Container(
                      padding: EdgeInsets.only(top: 0.5,bottom: 0.5,left: 0.0,right: 0.0),
                      decoration:BoxDecoration(
                          borderRadius:BorderRadius.circular(5),
                          border: Border.all(color: Colors.green, width: 4),
                          color: Color(0xDC063280),
                      ),
                      child: TextButton.icon(
                          label: const Text('Redo', textAlign: TextAlign.justify, style: TextStyle(fontSize: 20, color: Colors.white),),
                          icon: Icon(Icons.redo, color: Colors.white,),
                          onPressed: () {
                            debugPrint('Not Removed Offset List value in Redo: ${widget.connectionListRedo}');
                            _connectionList.add(widget.connectionListRedo.last);
                            widget.connectionListRedo.removeLast();
                            debugPrint('Retrieved Offset value Redo: $_connectionList');
                            print('Pressed Undo btn');
                          }),
                    ),
                  ),
                  Align(
                    alignment: FractionalOffset.bottomLeft,
                    child:
                    Container(
                        padding: EdgeInsets.only(top: 0.5,bottom: 0.5,left: 0.0,right: 0.0),
                        decoration:BoxDecoration(
                          borderRadius:BorderRadius.circular(5),
                          border: Border.all(color: Colors.green, width: 4),
                          color: Color(0xDC063280),
                        ),
                        child:
                        TextButton.icon(
                            label: const Text('Line', textAlign: TextAlign.justify, style: TextStyle(fontSize: 20, color: Colors.white),),
                            icon: Icon(Icons.create, color: Colors.white),
                            onPressed: () {
                              print('Pressed Line btn');
                            })
                    ),
                  ),
                  Align(
                    alignment: FractionalOffset.bottomLeft,
                    child:
                    Container(
                      padding: EdgeInsets.only(top: 0.5,bottom: 0.5,left: 3.5,right: 0.0),
                        decoration:BoxDecoration(
                            borderRadius:BorderRadius.circular(5),
                          border: Border.all(color: Colors.green, width: 4),
                          color: Color(0xDC063280),
                        ),
                        child:
                        DropdownButton(
                          icon: const Icon(Icons.arrow_drop_down, color: Colors.white, size: 30,),
                          style: const TextStyle(
                            color: Colors.white,
                            fontSize: 20,
                          ),
                          value: dropdownvalue,
                          dropdownColor: Colors.redAccent,
                          items: items.map((String items) {
                          return DropdownMenuItem(child: Text(items),
                          value: items,
                          );
                        }).toList(),
                          onChanged: (String? value){
                          setState(() {
                            dropdownvalue = value!;
                          });
                          },
                        ),
                    ),
                  ),
                  Align(
                    alignment: FractionalOffset.bottomLeft,
                    child:
                    Container(
                      padding: EdgeInsets.only(top: 0.5,bottom: 0.5,left: 0.0,right: 0.0),
                      decoration:BoxDecoration(
                          borderRadius:BorderRadius.circular(5),
                        border: Border.all(color: Colors.green, width: 4),
                        color: Color(0xDC063280),
                      ),
                      child: TextButton.icon(
                          label: const Text('My Videos', textAlign: TextAlign.justify, style: TextStyle(fontSize: 20, color: Colors.white),),
                          icon: Icon(Icons.image, color: Colors.white,),
                          onPressed: () {
                            print('Pressed Video btn');
                          }),
                    ),
                  ),
                  Align(
                    alignment: FractionalOffset.bottomLeft,
                    child:
                    Container(
                        padding: EdgeInsets.only(top: 0.5,bottom: 0.5,left: 0.0,right: 0.0),
                        decoration:BoxDecoration(
                            borderRadius:BorderRadius.circular(5),
                          border: Border.all(color: Colors.green, width: 4),
                          color: Color(0xDC063280),
  
                        ),
                        child:
                        TextButton.icon(
                            label: const Text('Notifications', textAlign: TextAlign.justify, style: TextStyle(fontSize: 20, color: Colors.white),),
                            // icon: Icon(Icons.align_vertical_center_sharp, color: Colors.white),
                            icon: Icon(Icons.notifications, color: Colors.white),
  
                            onPressed: () {
                              print('Pressed Notifications btn');
                            })
                    ),
                  ),
                  Align(
                    alignment: FractionalOffset.bottomLeft,
                    child:
                    Container(
                      padding: EdgeInsets.only(top: 0.5,bottom: 0.5,left: 3.5,right: 0.0),
                      decoration:BoxDecoration(
                          borderRadius:BorderRadius.circular(5),
                          border: Border.all(color: Colors.redAccent, width: 4),
                          color:Colors.black87
                      ),
                      child:
                      DropdownButton(
                        icon: const Icon(Icons.arrow_drop_down, color: Colors.white, size: 30,),
                        style: const TextStyle(
                          color: Colors.white,
                          fontSize: 20,
                        ),
                        value: dropdownvalue1,
                        dropdownColor: Colors.redAccent,
                        items: items1.map((String items) {
                          return DropdownMenuItem(child: Text(items),
                            value: items,
                          );
                        }).toList(),
                        onChanged: (String? value){
                          setState(() {
                            dropdownvalue1 = value!;
                          });
                        },
                      ),
                    ),
                  ),
  
                ],
              ),
            ),
          )),
        ),
        doubleTapTimeConsider: 300,
        longPressTimeConsider: 350,
        onTap: onTap,
        onMoveStart: onMoveStart,
        onMoveEnd: onMoveEnd,
        onMoveUpdate: onMoveUpdate,
        onScaleStart: onScaleStart,
        onScaleUpdate: onScaleUpdate,
        onScaleEnd: onScaleEnd,
        bypassTapEventOnDoubleTap: false,
      );
  
    }
  
    void onScaleEnd() {
      setLastEventName('onScaleEnd');
      print('onScaleEnd');
    }
  
    void onScaleStart(initialFocusPoint) {
      setLastEventName('onScaleStart');
      print('onScaleStart - initialFocusPoint: ' + initialFocusPoint.toString());
    }
  
    void onLongPress(pointer, localPos, position) {
      setLastEventName('onLongPress');
      print('onLongPress - pos: ' + localPos.toString());
    }
  
    void onDoubleTap(localPos, position) {
      setLastEventName('onDoubleTap');
      print('onDoubleTap - pos: ' + localPos.toString());
  
      _connectionList.removeLast();
    }
  
    void onTap(event) {
      setLastEventName('onTap');
      print('onTap - pos: ' + event.localPos.toString());
    }
  
    Future&lt;void&gt; onMoveUpdate(MoveEvent event) async {
      setLastEventName('onMoveUpdate');
      print('onMoveUpdate - pos: ${event.localPos} delta: ${event.delta}');
    }
  
    void onMoveStart(localPos) {
      setLastEventName('onMoveStart');
      print('onMoveStart - pos: $localPos');
      pos1 = localPos;
      debugPrint('pos1 Local pos: ${pos1.localPos}');
      debugPrint('pos1 delta pos: ${pos1.delta}');
    }
  
    void onMoveEnd(localPos) {
      setLastEventName('onMoveEnd');
      print('onMoveEnd - pos: $localPos');
      pos2 = localPos;
      debugPrint('pos2 Local pos: ${pos2.localPos}');
      debugPrint('position1 ${pos1.localPos}, position2 ${pos2.localPos}');
  
      List&lt;Offset&gt; _offsets = [];
      _offsets.add(pos1.localPos);
      _offsets.add(pos2.localPos);
      _connectionList.add(_offsets);
  
      widget.connectionListRedo = [];
  
      debugPrint('Offset List value: ${_offsets}, List: $_connectionList');
      LinePainter(pos1.localPos, pos2.localPos, _connectionList);
    }
  
    void onScaleUpdate(ScaleEvent event) {
      setLastEventName('onScaleUpdate');
      print(
          'onScaleUpdate - changedFocusPoint:  ${event.focalPoint} ; scale: ${event.scale} ;Rotation: ${event.rotationAngle}');
    }
  }</code></pre>
  </div>
  </div>
  </p>
  <p>Since I'm new to Flutter, there'll be some unwanted code. Please ignore those.</p>