I am working on an object recognition application with Flutter.
When the object is detected, it shows on the screen by covering it with container.
I want to convey the title of the detected object to the user audibly. It takes the title from the list named Results and displays it as a map.
I got it to speak the specified texts with TextToSpeech, but I don't know how to do it in real time.
List<Widget> _renderBoxes() {
return widget.results.map((re) {
var _x = re["rect"]["x"];
var _w = re["rect"]["w"];
var _y = re["rect"]["y"];
var _h = re["rect"]["h"];
var scaleW, scaleH, x, y, w, h;
if (widget.screenH / widget.screenW >
widget.previewH / widget.previewW) {
scaleW = widget.screenH / widget.previewH * widget.previewW;
scaleH = widget.screenH;
var difW = (scaleW - widget.screenW) / scaleW;
x = (_x - difW / 2) * scaleW;
w = _w * scaleW;
if (_x < difW / 2) w -= (difW / 2 - _x) * scaleW;
y = _y * scaleH;
h = _h * scaleH;
} else {
scaleH = widget.screenW / widget.previewW * widget.previewH;
scaleW = widget.screenW;
var difH = (scaleH - widget.screenH) / scaleH;
x = _x * scaleW;
w = _w * scaleW;
y = (_y - difH / 2) * scaleH;
h = _h * scaleH;
if (_y < difH / 2) h -= (difH / 2 - _y) * scaleH;
}
return Positioned(
left: math.max(0, x),
top: math.max(0, y),
width: w,
height: h,
child: Container(
padding: const EdgeInsets.only(top: 5.0, left: 5.0),
decoration: BoxDecoration(
border: Border.all(
color: Colors.amber,
width: 1.0,
),
),
child: Text(
"${re["detectedClass"]} ${(re["confidenceInClass"] * 100).toStringAsFixed(0)}%",
style: const TextStyle(
color: Colors.amber,
fontSize: 14.0,
fontWeight: FontWeight.bold,
),
),
),
);
}).toList();
}
The method I tried is
into the build
_res = Map.fromIterable(widget.results, value: (e) => e.detectedClass)
as String;
add _res value
#override
void initState() {
super.initState();
_textToSpeech.speak(_res);
}
I called it inside the method but it gave an error: "type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String' in type cast" and "Each child must be laid out exactly once.
"
Related
In my App i have to make Speedo Meter to display users speed,
I created Design with Custom Ranges Successfully as (0 2 5 10 25 50 100 150 200 300 500 1000) as below.
As above image, Design has been done that i want.
But in this, problem is when i set value of Range Pointer and Needle Pointer to 60 its display needle pointer and range pointer is greater than 150. So please help me to how i can solve the problem.
And Second, how i can Display 1Gbps instead of 1000,
Below is My Source Code.
SfRadialGauge(axes: <RadialAxis>[
RadialAxis(
minimum: 0,
maximum: 1000,
showLastLabel: true,
onCreateAxisRenderer: () {
final CustomAxisRenderer renderer =
CustomAxisRenderer();
return renderer;
},
axisLabelStyle:
GaugeTextStyle(color: Colors.white),
axisLineStyle: AxisLineStyle(
thickness: 15.0,
color: Colors.blueGrey[300]),
minorTicksPerInterval: 1,
minorTickStyle: MinorTickStyle(
color: Colors.blueGrey[200], length: 7.0),
majorTickStyle: MajorTickStyle(
color: Colors.blueGrey[300],
length: 10.0),
pointers: <GaugePointer>[
NeedlePointer(
value: 60,
// speed ?? 0.0,
enableAnimation: true,
needleStartWidth: 0,
needleEndWidth: 5,
needleColor: Colors.black,
knobStyle: KnobStyle(
color: Colors.white,
borderColor: Colors.black,
knobRadius: 0.06,
borderWidth: 0.04),
tailStyle: TailStyle(
color: Colors.black,
width: 5,
length: 0.15)),
RangePointer(
value: 60,
width: 15.0,
enableAnimation: true,
color:
Color.fromARGB(255, 30, 64, 124)),
],
annotations: <GaugeAnnotation>[
GaugeAnnotation(
widget: Text(
curSpeed + " $unit",
style:
Themes.getTextStyleWhite(context),
),
positionFactor: 1,
angle: 90,
)
],
)
]),
class CustomAxisRenderer extends RadialAxisRenderer {
CustomAxisRenderer() : super();
/// Generated the 9 non-linear interval labels from 0 to 150
/// instead of actual generated labels.
#override
List<CircularAxisLabel> generateVisibleLabels() {
final List<CircularAxisLabel> _visibleLabels = <CircularAxisLabel>[];
for (num i = 0; i < 12; i++) {
final double _value = _calculateLabelValue(i);
final CircularAxisLabel label = CircularAxisLabel(
this.axis.axisLabelStyle, _value.toInt().toString(), i, false);
label.value = _value;
_visibleLabels.add(label);
_visibleLabels.map((e) => print("val:- ${e.value}"));
}
return _visibleLabels;
}
/// Returns the factor(0 to 1) from value to place the labels in an axis.
#override
double valueToFactor(double value) {
// 2 5 10 25 50 100 150 200 300 500 1000
if (value >= 0 && value <= 2) {
return (value * 0.125) / 2;
} else if (value > 2 && value <= 5) {
return (((value - 2) * 0.125) / (5 - 2)) + (1 * 0.125);
} else if (value > 5 && value <= 10) {
return (((value - 5) * 0.125) / (10 - 5)) + (2 * 0.125);
} else if (value > 10 && value <= 20) {
return (((value - 10) * 0.125) / (20 - 10)) + (3 * 0.125);
} else if (value > 25 && value <= 50) {
return (((value - 25) * 0.125) / (50 - 30)) + (4 * 0.125);
} else if (value > 50 && value <= 100) {
return (((value - 50) * 0.125) / (100 - 50)) + (5 * 0.125);
} else if (value > 100 && value <= 150) {
return (((value - 100) * 0.125) / (150 - 100)) + (6 * 0.125);
} else if (value > 150 && value <= 200) {
return (((value - 150) * 0.125) / (200 - 150)) + (7 * 0.125);
} else if (value > 200 && value <= 300) {
return (((value - 200) * 0.125) / (300 - 200)) + (8 * 0.125);
} else if (value > 300 && value <= 500) {
return (((value - 300) * 0.125) / (500 - 300)) + (9 * 0.125);
} else if (value > 500 && value <= 1000) {
return (((value - 500) * 0.125) / (1000 - 500)) + (10 * 0.125);
} else {
return 1;
}
}
/// To return the label value based on interval
double _calculateLabelValue(num value) {
if (value == 0) {
return 0;
} else if (value == 1) {
return 2;
} else if (value == 2) {
return 5;
} else if (value == 3) {
return 10;
} else if (value == 4) {
return 25;
} else if (value == 5) {
return 50;
} else if (value == 6) {
return 100;
} else if (value == 7) {
return 150;
} else if (value == 8) {
return 200;
} else if (value == 9) {
return 300;
} else if (value == 10) {
return 500;
} else {
return 1000;
}
}
}
Please Help me, Thank You.
I'm learning flutter recently, but I still don't understand the use of flutter canvas,
I hope to get your help, here.
How to using flutter implement this html5 canvas animation?
jsfiddle animation demo link
HTML code
margin: 0;
padding: 0;
background: #000000;
}
canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="mycanvas"></canvas>
<script type="text/javascript">
const mycanvas = document.getElementById('mycanvas')
const context = mycanvas.getContext('2d')
const canvasWidth = window.innerWidth
const canvasHeight = window.innerHeight
mycanvas.width = canvasWidth
mycanvas.height = canvasHeight
console.log(canvasWidth, canvasHeight);
// 创建渐变
function createGradient(context, p0, p1) {
const gradient = context.createLinearGradient(p0.x, p0.y, p1.x, p1.y)
gradient.addColorStop(0, 'rgba(255, 255, 0, 0)')
gradient.addColorStop(1, 'rgba(255, 255, 0, 1)')
return gradient
}
// 绘制曲线
function createCurveLine(points) {
const gradient = createGradient(context, points[0], points[points.length - 1])
context.beginPath()
context.moveTo(points[0].x, points[0].y)
// 参数 points 是曲线上一部分连续点的集合,我们用 lineTo 把这些点连结起来,就近似的得到了曲线
for (let i = 0; i < points.length; i++) {
const p = points[i]
context.lineTo(p.x, p.y)
}
context.moveTo(points[0].x, points[0].y)
context.strokeStyle = gradient
context.lineCap = 'round'
context.lineWidth = 5
context.shadowColor = 'rgba(255, 0, 255, 1)'
context.shadowBlur = 10
context.stroke()
}
const P0 = {
x: 100,
y: canvasHeight / 2
}
const P1 = {
x: canvasWidth / 2,
y: canvasHeight / 2 - 200
}
const P2 = {
x: canvasWidth - 100,
y: canvasHeight / 2
}
let t0 = 0
let t1 = 0
let points = [] // 存储曲线上点的集合
const lineLength = 0.3;
function draw() {
context.clearRect(0, 0, canvasWidth, canvasHeight);
if (t1 < lineLength) {
t0 = 0;
}
if (t0 > 1 - lineLength) {
t1 = 1;
}
const currentPoint = {
x: computeCurvePoint(P0.x, P1.x, P2.x, t1),
y: computeCurvePoint(P0.y, P1.y, P2.y, t1)
}
// 每当 t1 变化时,就将对应的点添加到 points 集合中
points.push(currentPoint)
const len = points.length
context.save()
if (len > 1) {
createCurveLine(points.slice(Math.floor(len * t0), Math.max(Math.ceil(len * t1), 2)))
}
context.restore()
t0 += 0.005
t1 += 0.005
if (t0 > 1 && t1 > 1) {
t0 = 0
t1 = 0
points = []
}
requestAnimationFrame(draw)
}
draw()
/*!
* 计算二次贝塞尔曲线上的点
* #param {Number} p0 起始点
* #param {Number} p1 控制点
* #param {Number} p2 结束点
* #param {Number} t 0-1的集合
* #return {Number} 返回计算后的点
*/
function computeCurvePoint(p0, p1, p2, t) {
return (1 - t) * (1 - t) * p0 + 2 * t * (1 - t) * p1 + t * t * p2
}
function arc(...points) {
points.forEach(p => {
context.beginPath()
context.arc(p.x, p.y, 3, 0, Math.PI * 2)
context.stroke();
});
}
</script>
</body>
</html>
Im trying to pass data from a child widget to a parent widget using callback
so IM having this error
setState() or markNeedsBuild() called during build.
and I know its because of calling "callback" set msg before returning the stack(during building of child , superclass call setState :( )
widget.setmsg(msg);
return Stack(children: widget.model == posenet ? _renderKeypoints() : null);
SO how can I return renderKeypoints() widget and return msg to super? or is there a way to print msg immediately in the screen (I get the value of msg after having calculation in renderkeypoint ?
Subclass code :
typedef void IntCallback(String id);
// ignore: must_be_immutable
class BndBox extends StatefulWidget {
final List<dynamic> results;
final int previewH;
final int previewW;
final double screenH;
final double screenW;
final String model;
final IntCallback setmsg;
BndBox(this.results, this.previewH, this.previewW, this.screenH, this.screenW,
this.model, this.setmsg);
#override
_BndBoxState createState() => _BndBoxState();
}
class _BndBoxState extends State<BndBox> {
#override
Widget build(BuildContext context) {
String msg = "";
List<Widget> _renderKeypoints() {
var lists = <Widget>[];
var kx = [10.9];
kx.removeAt(0);
widget.results.forEach((re) {
var list = re["keypoints"].values.map<Widget>((k) {
var _x = k["x"];
var _y = k["y"];
var scaleW, scaleH, x, y;
kx.add(k["x"]);
if (widget.screenH / widget.screenW >
widget.previewH / widget.previewW) {
scaleW = widget.screenH / widget.previewH * widget.previewW;
scaleH = widget.screenH;
print("scaleW");
print(scaleW);
print("scaleH");
print(scaleH);
var difW = (scaleW - widget.screenW) / scaleW;
x = (_x - difW / 2) * scaleW;
y = _y * scaleH;
} else {
scaleH = widget.screenW / widget.previewW * widget.previewH;
scaleW = widget.screenW;
var difH = (scaleH - widget.screenH) / scaleH;
x = _x * scaleW;
y = (_y - difH / 2) * scaleH;
}
return Stack(children: [
Positioned(
left: x - 6,
top: y - 6,
width: 100,
height: 12,
child: Container(
child: Text(
"● ${k["part"]}",
style: TextStyle(
color: Color.fromRGBO(37, 213, 253, 1.0),
fontSize: 12.0,
),
),
),
),
]);
}).toList();
lists..addAll(list);
});
try {
if (((kx[3] - kx[5]).abs() <= 0.05) &&
((kx[3] - kx[11]).abs() <= 0.1)) {
msg = "RIGHT POSE";
} else if (((kx[3] - kx[5]) > 0.05 && (kx[3] - kx[5]) < 0.1) &&
(((kx[3] - kx[11]) > 0.1) && (kx[3] - kx[11]) < 0.2)) {
msg = "WRONG POSE";
} else {
msg = "UNDEFINED";
}
} catch (Exception) {
msg = "EXCEPTION";
}
return lists;
}
// widget.setmsg(msg); //error here
return Stack(
children: widget.model == posenet ? _renderKeypoints() : SizedBox(),
}
}
return Stack(children: widget.model == posenet ? _renderKeypoints() : SizedBox());
the solution does not need call back ,,
what I wanted has been solved
return Stack(children: <Widget>[
Stack(
children: widget.model == posenet ? _renderKeypoints() : null,
),
Text(msg)
]);
I found some genius code. But I do not understand how they designed the marker pin
Is the MarkerPin made from svg in some way or did they just come up with the design out of maths?
I have this svg icon I would like to use. So how would i go about translating that to the code below? I may be stupid and they are completely unrelated to svg.
L.MarkerPin = L.CircleMarker.extend({
_updatePath: function () {
this._renderer._updateMarkerPin(this);
},
_containsPoint: function (p) {
var r = this._radius;
var insideCircle =
p.add([0, r * 2]).distanceTo(this._point) <= r + this._clickTolerance();
var a = this._point,
b = a.subtract([0.58 * r, r]),
c = a.subtract([-0.58 * r, r]);
var insideTriangle = true;
var ap_x = p.x - a.x;
var ap_y = p.y - a.y;
var p_ab = (b.x - a.x) * ap_y - (b.y - a.y) * ap_x > 0;
var p_ac = (c.x - a.x) * ap_y - (c.y - a.y) * ap_x > 0;
var p_bc = (c.x - b.x) * (p.y - b.y) - (c.y - b.y) * (p.x - b.x) > 0;
if (p_ac === p_ab) insideTriangle = false;
if (p_bc !== p_ab) insideTriangle = false;
return insideTriangle || insideCircle;
}
});
Jsfiddle with complete example:
https://jsfiddle.net/n2jf5c4q/
The code you posted is only to check if a point (f.e. a click position) is in the area of the Pin. I think this is made because the creator don't wanted that the click event is fired when it is clicked on the area of a circle.
What you mean is this code:
ctx.beginPath();
ctx.moveTo(p.x, p.y);
ctx.lineTo(p.x - 0.58 * r, p.y - r);
ctx.arc(p.x, p.y - 2 * r, r, -Math.PI * 1.161, Math.PI * 0.161);
ctx.closePath();
This is normal canvas drawing and has nothing to do with svg
Update
I tried a little bit around and i found a way, but this is not supported for all browsers.
You can use Path2D render the svg as canvas path (maybe you have to resize the svg)
window.p = new Path2D("M0-0.1h20.8v20.9H0V-0.1z M0.5,0.4v19.9h19.8V0.4H0.5z M19,14h-3.2l1.6,3.4h-1.7L14,14H6.7l-1.6,3.4H3.3L4.9,14H1.8v-1.6 h3.9l0.8-1.6H4.1V9.1h12.5v1.6h-2.4l0.8,1.6h4V14z M7.4,12.4h5.8l-0.7-1.6H8.2L8.1,11l-0.3,0.6L7.4,12.4z");
L.Canvas.include({
_updateCircle: function (layer) {
if (!this._drawing || layer._empty()) { return; }
var p = layer._point,
ctx = this._ctx,
r = Math.max(Math.round(layer._radius), 1),
s = (Math.max(Math.round(layer._radiusY), 1) || r) / r;
if (s !== 1) {
ctx.save();
ctx.scale(1, s);
}
ctx.beginPath();
ctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);
if (s !== 1) {
ctx.restore();
}
var x = p.x-10; // -10 because of ~20 is the img size
var y = p.y-10;
ctx.translate(x,y);
ctx.fill(window.p);
//this._fillStroke(ctx, layer);
},
});
var canvasRenderer = L.canvas();
new L.CircleMarker([51.505, -0.09], {
renderer: canvasRenderer
}).bindPopup('hello').addTo(mymap);
I am using flutter_map with yandex map like below. When I mark a location, Getting location lat and lon are wrong. So If I draw a polygon on the map, It drawn on wrong location. How to fix this?
FlutterMap(
options: MapOptions(
center: LatLng(41.334554,36.269617),
zoom: 11.0,
maxZoom: 18,
minZoom: 5,
plugins: [
DragMarkerPlugin(),
],
onTap: (value){
print(value.toString());
markLocation(value);
},
),
layers: [
TileLayerOptions(
urlTemplate: 'https://core-sat.maps.yandex.net/tiles?l=sat&v=3.569.0&x={x}&y={y}&z={z}&lang=tr_TR'
),
TileLayerOptions(
urlTemplate: 'http://vec{s}.maps.yandex.net/tiles?l=skl&v=20.06.03&z={z}&x={x}&y={y}&scale=1&lang=tr_TR',
subdomains: ['01', '02', '03', '04'],
backgroundColor: Colors.transparent
),
CircleLayerOptions(
circles: _circles
),
PolygonLayerOptions(
polygons: getPolygons()
),
DragMarkerPluginOptions(
markers: _markers
)
],
mapController: _mapController,
)
Actual position of polygon:
And How to looks on device?
I used custom csr for solve this problem. Thanks to dmitrienkop for his answer.
https://github.com/fleaflet/flutter_map/issues/642
import 'dart:math' as math;
import 'package:flutter_map/plugin_api.dart';
import 'package:latlong/latlong.dart';
class Epsg3395 extends Earth {
#override
final String code = 'EPSG:3395';
#override
final Projection projection = const Mercator();
#override
final Transformation transformation = const Transformation(_scale, 0.5, -_scale, 0.5);
static const num _scale = 0.5 / (math.pi * Mercator.r);
const Epsg3395() : super();
}
class Mercator extends Projection {
static const int r = 6378137;
static const double rMinor = 6356752.314245179;
static final Bounds<double> _bounds = Bounds<double>(
CustomPoint<double>(-20037508.34279, -15496570.73972),
CustomPoint<double>(20037508.34279, 18764656.23138),
);
const Mercator() : super();
#override
Bounds<double> get bounds => _bounds;
#override
CustomPoint project(LatLng latlng) {
var d = math.pi / 180;
var y = latlng.latitude * d;
var tmp = rMinor / r;
var e = math.sqrt(1 - tmp * tmp);
var con = e * math.sin(y);
var ts = math.tan(math.pi / 4 - y / 2) / math.pow((1 - con) / (1 + con), e / 2);
y = -r * math.log(math.max(ts, 1E-10));
return CustomPoint(latlng.longitude * d * r, y);
}
#override
LatLng unproject(CustomPoint point) {
var d = 180 / math.pi;
var tmp = rMinor / r;
var e = math.sqrt(1 - tmp * tmp);
var ts = math.exp(-point.y / r);
var phi = math.pi / 2 - 2 * math.atan(ts);
for (var i = 0, dphi = 0.1, con; i < 15 && dphi.abs() > 1e-7; i++) {
con = e * math.sin(phi);
con = math.pow((1 - con) / (1 + con), e / 2);
dphi = math.pi / 2 - 2 * math.atan(ts * con) - phi;
phi += dphi;
}
return LatLng(phi * d, point.x * d / r);
}
}