map image updates
parent
332d7748b7
commit
7300150ff4
|
@ -43,7 +43,8 @@ describe("<FarmDesigner/>", () => {
|
|||
cameraCalibrationData: {
|
||||
scale: undefined, rotation: undefined,
|
||||
offset: { x: undefined, y: undefined },
|
||||
origin: undefined
|
||||
origin: undefined,
|
||||
calibrationZ: undefined
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -243,4 +243,5 @@ export interface CameraCalibrationData {
|
|||
y: string | undefined;
|
||||
},
|
||||
origin: string | undefined;
|
||||
calibrationZ: string | undefined;
|
||||
}
|
||||
|
|
|
@ -82,7 +82,8 @@ function fakeProps(): GardenMapProps {
|
|||
cameraCalibrationData: {
|
||||
scale: undefined, rotation: undefined,
|
||||
offset: { x: undefined, y: undefined },
|
||||
origin: undefined
|
||||
origin: undefined,
|
||||
calibrationZ: undefined
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ describe("<MapImage />", () => {
|
|||
offset: { x: undefined, y: undefined },
|
||||
origin: undefined,
|
||||
rotation: undefined,
|
||||
scale: undefined
|
||||
scale: undefined,
|
||||
calibrationZ: undefined
|
||||
},
|
||||
mapTransformProps: {
|
||||
gridSize: { x: 0, y: 0 },
|
||||
|
@ -40,13 +41,6 @@ describe("<MapImage />", () => {
|
|||
expect(wrapper.html()).toEqual("<image></image>");
|
||||
});
|
||||
|
||||
it("doesn't render placeholder image", () => {
|
||||
const p = fakeProps();
|
||||
p.image && (p.image.body.attachment_url = "/placehold.");
|
||||
const wrapper = mount(<MapImage {...p} />);
|
||||
expect(wrapper.html()).toEqual("<image></image>");
|
||||
});
|
||||
|
||||
interface ExpectedData {
|
||||
size: { width: number, height: number };
|
||||
sx: number;
|
||||
|
@ -74,11 +68,14 @@ describe("<MapImage />", () => {
|
|||
const INPUT_SET_1 = fakeProps();
|
||||
INPUT_SET_1.image && (INPUT_SET_1.image.body.meta.x = 0);
|
||||
INPUT_SET_1.image && (INPUT_SET_1.image.body.meta.y = 0);
|
||||
INPUT_SET_1.image && (INPUT_SET_1.image.body.meta.z = 0);
|
||||
INPUT_SET_1.image && (INPUT_SET_1.image.body.meta.name = "rotated_image");
|
||||
INPUT_SET_1.cameraCalibrationData = {
|
||||
offset: { x: "50", y: "75" },
|
||||
origin: "\"TOP_RIGHT\"",
|
||||
rotation: "-57.45",
|
||||
scale: "0.8041"
|
||||
scale: "0.8041",
|
||||
calibrationZ: "0"
|
||||
};
|
||||
INPUT_SET_1.mapTransformProps = {
|
||||
gridSize: { x: 5900, y: 2900 },
|
||||
|
@ -87,12 +84,15 @@ describe("<MapImage />", () => {
|
|||
INPUT_SET_1.sizeOverride = { width: 480, height: 640 };
|
||||
|
||||
const INPUT_SET_2 = cloneDeep(INPUT_SET_1);
|
||||
INPUT_SET_2.image && (INPUT_SET_2.image.body.meta = { x: 221, y: 308, z: 1 });
|
||||
INPUT_SET_2.image && (INPUT_SET_2.image.body.meta = {
|
||||
x: 221, y: 308, z: 1, name: "marked_image"
|
||||
});
|
||||
INPUT_SET_2.cameraCalibrationData.origin = "TOP_RIGHT";
|
||||
INPUT_SET_2.mapTransformProps.quadrant = 1;
|
||||
|
||||
const INPUT_SET_3 = cloneDeep(INPUT_SET_2);
|
||||
INPUT_SET_3.mapTransformProps.quadrant = 2;
|
||||
INPUT_SET_3.image && (INPUT_SET_3.image.body.meta.name = "calibration_result");
|
||||
|
||||
const INPUT_SET_4 = cloneDeep(INPUT_SET_3);
|
||||
INPUT_SET_4.mapTransformProps.quadrant = 3;
|
||||
|
@ -136,4 +136,24 @@ describe("<MapImage />", () => {
|
|||
size: expectedSize, sx: 1, sy: 1, tx: 5436.016, ty: 2259.688
|
||||
});
|
||||
|
||||
it("doesn't render placeholder image", () => {
|
||||
const p = INPUT_SET_1;
|
||||
p.image && (p.image.body.attachment_url = "/placehold.");
|
||||
const wrapper = mount(<MapImage {...p} />);
|
||||
expect(wrapper.html()).toEqual("<image></image>");
|
||||
});
|
||||
|
||||
it("doesn't render image taken at different height than calibration", () => {
|
||||
const p = INPUT_SET_1;
|
||||
p.image && (p.image.body.meta.z = 100);
|
||||
const wrapper = mount(<MapImage {...p} />);
|
||||
expect(wrapper.html()).toEqual("<image></image>");
|
||||
});
|
||||
|
||||
it("doesn't render images that are not adjusted for camera rotation", () => {
|
||||
const p = INPUT_SET_1;
|
||||
p.image && (p.image.body.meta.name = "na");
|
||||
const wrapper = mount(<MapImage {...p} />);
|
||||
expect(wrapper.html()).toEqual("<image></image>");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,9 +5,12 @@ import { fakeImage } from "../../../../__test_support__/fake_state/resources";
|
|||
|
||||
describe("<ImageLayer/>", () => {
|
||||
function fakeProps(): ImageLayerProps {
|
||||
const image = fakeImage();
|
||||
image.body.meta.z = 0;
|
||||
image.body.meta.name = "rotated_image";
|
||||
return {
|
||||
visible: true,
|
||||
images: [fakeImage()],
|
||||
images: [image],
|
||||
mapTransformProps: {
|
||||
quadrant: 2, gridSize: { x: 3000, y: 1500 }
|
||||
},
|
||||
|
@ -15,7 +18,8 @@ describe("<ImageLayer/>", () => {
|
|||
offset: { x: "0", y: "0" },
|
||||
origin: "TOP_LEFT",
|
||||
rotation: "0",
|
||||
scale: "1"
|
||||
scale: "1",
|
||||
calibrationZ: "0"
|
||||
},
|
||||
sizeOverride: { width: 10, height: 10 }
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ import { MapTransformProps } from "../interfaces";
|
|||
import { CameraCalibrationData } from "../../interfaces";
|
||||
import { TaggedImage } from "../../../resources/tagged_resources";
|
||||
import { MapImage } from "../map_image";
|
||||
import { reverse } from "lodash";
|
||||
import { reverse, cloneDeep } from "lodash";
|
||||
|
||||
export interface ImageLayerProps {
|
||||
visible: boolean;
|
||||
|
@ -19,7 +19,7 @@ export function ImageLayer(props: ImageLayerProps) {
|
|||
} = props;
|
||||
return <g id="image-layer">
|
||||
{visible &&
|
||||
reverse(images).map(img =>
|
||||
reverse(cloneDeep(images)).map(img =>
|
||||
<MapImage
|
||||
image={img}
|
||||
key={"image_" + img.body.id}
|
||||
|
|
|
@ -13,6 +13,22 @@ const parse = (str: string | undefined) => {
|
|||
return !isNaN(parsed) ? parsed : undefined;
|
||||
};
|
||||
|
||||
/* Check if the image has been rotated according to the calibration value. */
|
||||
const isRotated = (name: string | undefined) => {
|
||||
return name &&
|
||||
(name.includes("rotated")
|
||||
|| name.includes("marked")
|
||||
|| name.includes("calibration_result"));
|
||||
};
|
||||
|
||||
/* Check if the calibration data is valid for the image provided using z. */
|
||||
const cameraZCheck =
|
||||
(imageZ: number | undefined, calibZ: string | undefined) => {
|
||||
const calibrationZ = parse(calibZ);
|
||||
return isNumber(imageZ) && isNumber(calibrationZ) &&
|
||||
Math.abs(imageZ - calibrationZ) < 5;
|
||||
};
|
||||
|
||||
interface ImageSize {
|
||||
width: number;
|
||||
height: number;
|
||||
|
@ -20,8 +36,8 @@ interface ImageSize {
|
|||
|
||||
/* Get the size of the image at the URL. Allow overriding for tests. */
|
||||
const getImageSize = (url: string, size?: ImageSize): ImageSize => {
|
||||
if (size) { return size; }
|
||||
if (url.includes("placehold")) { return { width: 0, height: 0 }; }
|
||||
if (size) { return size; }
|
||||
const imageData = new Image();
|
||||
imageData.src = url;
|
||||
return {
|
||||
|
@ -102,9 +118,8 @@ export interface MapImageProps {
|
|||
*/
|
||||
export function MapImage(props: MapImageProps) {
|
||||
const { image, cameraCalibrationData, sizeOverride } = props;
|
||||
const { scale, rotation, offset, origin } = cameraCalibrationData;
|
||||
const { scale, offset, origin, calibrationZ } = cameraCalibrationData;
|
||||
const imageScale = parse(scale);
|
||||
const imageRotation = parse(rotation);
|
||||
const imageOffsetX = parse(offset.x);
|
||||
const imageOffsetY = parse(offset.y);
|
||||
const imageOrigin = origin ? origin.split("\"").join("") : undefined;
|
||||
|
@ -113,12 +128,14 @@ export function MapImage(props: MapImageProps) {
|
|||
/* Check if the image exists. */
|
||||
if (image) {
|
||||
const imageUrl = image.body.attachment_url;
|
||||
const { x, y } = image.body.meta;
|
||||
const { x, y, z } = image.body.meta;
|
||||
const imageAnnotation = image.body.meta.name;
|
||||
const { width, height } = getImageSize(imageUrl, sizeOverride);
|
||||
|
||||
/* Check for all necessary camera calibration and image data. */
|
||||
if (isNumber(x) && isNumber(y) && height > 0 && width > 0 &&
|
||||
isNumber(imageScale) && isNumber(imageRotation) &&
|
||||
isNumber(imageScale) && imageScale > 0 &&
|
||||
cameraZCheck(z, calibrationZ) && isRotated(imageAnnotation) &&
|
||||
isNumber(imageOffsetX) && isNumber(imageOffsetY) && imageOrigin) {
|
||||
/* Use pixel to coordinate scale to scale image. */
|
||||
const size = { x: width * imageScale, y: height * imageScale };
|
||||
|
|
|
@ -55,7 +55,7 @@ export function mapStateToProps(props: Everything) {
|
|||
const latestImages = _(selectAllImages(props.resources.index))
|
||||
.sortBy(x => x.body.id)
|
||||
.reverse()
|
||||
.take(5)
|
||||
.take(50)
|
||||
.value();
|
||||
|
||||
const { user_env } = props.bot.hardware;
|
||||
|
@ -67,6 +67,7 @@ export function mapStateToProps(props: Everything) {
|
|||
y: user_env["CAMERA_CALIBRATION_camera_offset_y"]
|
||||
},
|
||||
origin: user_env["CAMERA_CALIBRATION_image_bot_origin_location"],
|
||||
calibrationZ: user_env["CAMERA_CALIBRATION_camera_z"],
|
||||
};
|
||||
|
||||
return {
|
||||
|
|
|
@ -11,6 +11,7 @@ export interface Image {
|
|||
x: number | undefined;
|
||||
y: number | undefined;
|
||||
z: number | undefined;
|
||||
name?: string;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -43,9 +43,12 @@ export class Photos extends React.Component<PhotosProps, {}> {
|
|||
const i = this.props.currentImage;
|
||||
if (i) {
|
||||
const { meta } = i.body;
|
||||
return Object.keys(meta).sort().map(function (key, index) {
|
||||
return <MetaInfo key={index} attr={key} obj={meta} />;
|
||||
});
|
||||
return Object.keys(meta)
|
||||
.filter(key => ["x", "y", "z"].includes(key))
|
||||
.sort()
|
||||
.map((key, index) => {
|
||||
return <MetaInfo key={index} attr={key} obj={meta} />;
|
||||
});
|
||||
} else {
|
||||
return <MetaInfo attr={t("image")} obj={{ image: t("No meta data.") }} />;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue