Skip to content

Commit

Permalink
Yuhsuan/1843 control map border (#1870)
Browse files Browse the repository at this point in the history
* remove unused code

* refactor controlMap and catalogControlMap

* inherit controlMap

* remove unused code

* adjust control map min/max point to avoid border issue

* exclude zeros when finding catalog min/max

* update changelog

Co-authored-by: Angus Comrie <[email protected]>
  • Loading branch information
YuHsuan-Hwang and veggiesaurus authored May 30, 2022
1 parent 8d7e02c commit 92db739
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 130 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Hide code snippet option in the View menu when code snippet is disabled in the preferences ([#1856](https://github.com/CARTAvis/carta-frontend/issues/1856)).
* Fixed the rotation anchor offset of line regions ([#1739](https://github.com/CARTAvis/carta-frontend/issues/1739)).
* Fixed issue with exporting decimated data instead of full resolution data in spatial profiler ([#1546](https://github.com/CARTAvis/carta-frontend/issues/1546))
* Fixed larger position errors of projected contours, catalog overlays, and vector overlays near the border ([#1843](https://github.com/CARTAvis/carta-frontend/issues/1843)).

## [3.0.0-beta.3]

Expand Down
79 changes: 8 additions & 71 deletions src/models/CatalogControlMap.ts
Original file line number Diff line number Diff line change
@@ -1,102 +1,39 @@
import * as AST from "ast_wrapper";
import {CatalogStore} from "stores";
import {FrameStore} from "stores/Frame";
import {Point2D} from "./Point2D";
import {GL2} from "utilities";
import {ControlMap} from "models";

export class CatalogControlMap {
readonly source: FrameStore;
readonly destination: FrameStore;
readonly width: number;
readonly height: number;
minPoint: Point2D;
maxPoint: Point2D;
private gl2: WebGL2RenderingContext;
private texture: WebGLTexture;
private grid: Float32Array;
export class CatalogControlMap extends ControlMap {
private boundaryUpdated: boolean;

constructor(src: FrameStore, dst: FrameStore, astTransform: AST.FrameSet, width: number, height: number) {
this.source = src;
this.destination = dst;
this.width = width;
this.height = height;

let cleanUpTransform: boolean = false;

if (astTransform < 0) {
const copySrc = AST.copy(src.wcsInfo);
const copyDest = AST.copy(dst.wcsInfo);
AST.invert(copySrc);
AST.invert(copyDest);
astTransform = AST.convert(copySrc, copyDest, "");
AST.deleteObject(copySrc);
AST.deleteObject(copyDest);
cleanUpTransform = true;
}

super(src, dst, astTransform, width, height, false);
this.minPoint = {x: Number.MAX_VALUE, y: Number.MAX_VALUE};
this.maxPoint = {x: -Number.MAX_VALUE, y: -Number.MAX_VALUE};
this.boundaryUpdated = false;

if (cleanUpTransform) {
AST.deleteObject(astTransform);
}
}

hasTextureForContext = (gl2: WebGL2RenderingContext) => {
return gl2 === this.gl2 && this.texture && gl2.isTexture(this.texture);
};

updateCatalogBoundary = () => {
const catalogStore = CatalogStore.Instance;
const paddingX = Math.ceil(this.source.frameInfo.fileInfoExtended.width / this.width);
const paddingY = Math.ceil(this.destination.frameInfo.fileInfoExtended.height / this.height);
const srcMinMax = catalogStore.getFrameMinMaxPoints(this.source.frameInfo.fileId);
const dstMinMax = catalogStore.getFrameMinMaxPoints(this.destination.frameInfo.fileId);
const minX = srcMinMax.minX < dstMinMax.minX ? srcMinMax.minX : dstMinMax.minX;
const minY = srcMinMax.minY < dstMinMax.minY ? srcMinMax.minY : dstMinMax.minY;
const maxX = srcMinMax.maxX > dstMinMax.maxX ? srcMinMax.maxX : dstMinMax.maxX;
const maxY = srcMinMax.maxY > dstMinMax.maxY ? srcMinMax.maxY : dstMinMax.maxY;
if (this.minPoint.x > minX || this.minPoint.y > minY || this.maxPoint.x < maxX || this.maxPoint.y < maxY) {
this.minPoint = {x: minX - paddingX, y: minY - paddingY};
this.maxPoint = {x: maxX + paddingX, y: maxY + paddingY};
this.setMinMaxPoint(minX, minY, maxX, maxY);
this.boundaryUpdated = true;

const copySrc = AST.copy(this.source.wcsInfo);
const copyDest = AST.copy(this.destination.wcsInfo);
AST.invert(copySrc);
AST.invert(copyDest);
const astTransform = AST.convert(copySrc, copyDest, "");
AST.deleteObject(copySrc);
AST.deleteObject(copyDest);

this.minPoint = {x: minX - paddingX, y: minY - paddingY};
this.maxPoint = {x: maxX + paddingX, y: maxY + paddingY};
this.grid = AST.getTransformGrid(astTransform, this.minPoint.x, this.maxPoint.x, this.width, this.minPoint.y, this.maxPoint.y, this.height, true);

AST.deleteObject(astTransform);
this.setGrid();
}
};

getTextureX = (gl2: WebGL2RenderingContext) => {
if (gl2 !== this.gl2 || !this.texture || this.boundaryUpdated) {
getTextureX = (gl: WebGL2RenderingContext) => {
if (gl !== this.gl || !this.texture || this.boundaryUpdated) {
this.boundaryUpdated = false;
// Context has changed, texture needs to be regenerated
this.gl2 = gl2;
this.texture = this.gl2.createTexture();
this.gl2.activeTexture(GL2.TEXTURE1);
this.gl2.bindTexture(GL2.TEXTURE_2D, this.texture);
this.gl2.texParameteri(GL2.TEXTURE_2D, GL2.TEXTURE_MIN_FILTER, GL2.NEAREST);
this.gl2.texParameteri(GL2.TEXTURE_2D, GL2.TEXTURE_MAG_FILTER, GL2.NEAREST);
this.gl2.texParameteri(GL2.TEXTURE_2D, GL2.TEXTURE_WRAP_S, GL2.CLAMP_TO_EDGE);
this.gl2.texParameteri(GL2.TEXTURE_2D, GL2.TEXTURE_WRAP_T, GL2.CLAMP_TO_EDGE);
this.gl2.texImage2D(GL2.TEXTURE_2D, 0, GL2.RG32F, this.width, this.height, 0, GL2.RG, GL2.FLOAT, this.grid);
this.createTexture(gl);
}
return this.texture;
};

static IsWidthValid(width: number) {
return width >= 128 && width <= 1024;
}
}
95 changes: 38 additions & 57 deletions src/models/ControlMap.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,43 @@
import * as AST from "ast_wrapper";
import {FrameStore} from "stores/Frame";
import {Point2D} from "./Point2D";
import {GL2, subtract2D} from "utilities";
import {GL2} from "utilities";

export class ControlMap {
readonly source: FrameStore;
readonly destination: FrameStore;
readonly width: number;
readonly height: number;
readonly minPoint: Point2D;
readonly maxPoint: Point2D;
private readonly grid: Float32Array;
private texture: WebGLTexture;
private gl: WebGL2RenderingContext;
minPoint: Point2D;
maxPoint: Point2D;
texture: WebGLTexture;
gl: WebGL2RenderingContext;
private grid: Float32Array;

constructor(src: FrameStore, dst: FrameStore, astTransform: AST.FrameSet, width: number, height: number) {
constructor(src: FrameStore, dst: FrameStore, astTransform: AST.FrameSet, width: number, height: number, updateBoudary: boolean = true) {
this.source = src;
this.destination = dst;
this.width = width;
this.height = height;
if (updateBoudary) {
this.setMinMaxPoint(0, 0, this.source.frameInfo.fileInfoExtended.width - 1, this.source.frameInfo.fileInfoExtended.height - 1);
this.setGrid(astTransform);
}
}

setMinMaxPoint = (minX, minY, maxX, maxY) => {
const deltaX = (maxX - minX) / (this.width - 3);
const deltaY = (maxY - minY) / (this.height - 3);
this.minPoint = {x: minX - deltaX, y: minY - deltaY};
this.maxPoint = {x: maxX + deltaX * 2, y: maxY + deltaY * 2};
};

setGrid = (astTransform?: AST.FrameSet) => {
let cleanUpTransform: boolean = false;

if (astTransform < 0) {
const copySrc = AST.copy(src.wcsInfo);
const copyDest = AST.copy(dst.wcsInfo);
if (!astTransform || astTransform < 0) {
const copySrc = AST.copy(this.source.wcsInfo);
const copyDest = AST.copy(this.destination.wcsInfo);
AST.invert(copySrc);
AST.invert(copyDest);
astTransform = AST.convert(copySrc, copyDest, "");
Expand All @@ -33,66 +46,34 @@ export class ControlMap {
cleanUpTransform = true;
}

const paddingX = Math.ceil(src.frameInfo.fileInfoExtended.width / width);
const paddingY = Math.ceil(src.frameInfo.fileInfoExtended.height / height);
this.minPoint = {x: -paddingX, y: -paddingY};
this.maxPoint = {x: paddingX + src.frameInfo.fileInfoExtended.width, y: paddingY + src.frameInfo.fileInfoExtended.height};
this.grid = AST.getTransformGrid(astTransform, this.minPoint.x, this.maxPoint.x, width, this.minPoint.y, this.maxPoint.y, height, true);
this.grid = AST.getTransformGrid(astTransform, this.minPoint.x, this.maxPoint.x, this.width, this.minPoint.y, this.maxPoint.y, this.height, true);

if (cleanUpTransform) {
AST.deleteObject(astTransform);
}
}
};

getTextureX = (gl: WebGL2RenderingContext) => {
if (gl !== this.gl || !this.texture) {
// Context has changed, texture needs to be regenerated
this.gl = gl;
this.texture = this.gl.createTexture();
this.gl.activeTexture(GL2.TEXTURE1);
this.gl.bindTexture(GL2.TEXTURE_2D, this.texture);
this.gl.texParameteri(GL2.TEXTURE_2D, GL2.TEXTURE_MIN_FILTER, GL2.NEAREST);
this.gl.texParameteri(GL2.TEXTURE_2D, GL2.TEXTURE_MAG_FILTER, GL2.NEAREST);
this.gl.texParameteri(GL2.TEXTURE_2D, GL2.TEXTURE_WRAP_S, GL2.CLAMP_TO_EDGE);
this.gl.texParameteri(GL2.TEXTURE_2D, GL2.TEXTURE_WRAP_T, GL2.CLAMP_TO_EDGE);
this.gl.texImage2D(GL2.TEXTURE_2D, 0, GL2.RG32F, this.width, this.height, 0, GL2.RG, GL2.FLOAT, this.grid);
this.createTexture(gl);
}

return this.texture;
};

createTexture = (gl: WebGL2RenderingContext) => {
this.gl = gl;
this.texture = this.gl.createTexture();
this.gl.activeTexture(GL2.TEXTURE1);
this.gl.bindTexture(GL2.TEXTURE_2D, this.texture);
this.gl.texParameteri(GL2.TEXTURE_2D, GL2.TEXTURE_MIN_FILTER, GL2.NEAREST);
this.gl.texParameteri(GL2.TEXTURE_2D, GL2.TEXTURE_MAG_FILTER, GL2.NEAREST);
this.gl.texParameteri(GL2.TEXTURE_2D, GL2.TEXTURE_WRAP_S, GL2.CLAMP_TO_EDGE);
this.gl.texParameteri(GL2.TEXTURE_2D, GL2.TEXTURE_WRAP_T, GL2.CLAMP_TO_EDGE);
this.gl.texImage2D(GL2.TEXTURE_2D, 0, GL2.RG32F, this.width, this.height, 0, GL2.RG, GL2.FLOAT, this.grid);
};

hasTextureForContext = (gl: WebGL2RenderingContext) => {
return gl === this.gl && this.texture && gl.isTexture(this.texture);
};

getTransformedCoordinate(point: Point2D) {
const range = subtract2D(this.maxPoint, this.minPoint);
const shiftedPoint = subtract2D(point, this.minPoint);
const index2D: Point2D = {
x: (this.width * shiftedPoint.x) / range.x,
y: (this.height * shiftedPoint.y) / range.y
};

const indexFloor = {x: Math.floor(index2D.x), y: Math.floor(index2D.y)};
const step = {x: index2D.x - indexFloor.x, y: index2D.y - indexFloor.y};

// Get the four samples for bilinear interpolation
const index00 = indexFloor.y * this.width + indexFloor.x;
const index01 = (indexFloor.y + 1) * this.width + indexFloor.x;
const index10 = indexFloor.y * this.width + indexFloor.x + 1;
const index11 = (indexFloor.y + 1) * this.width + indexFloor.x + 1;
const f00 = {x: this.grid[index00 * 2], y: this.grid[index00 * 2 + 1]};
const f01 = {x: this.grid[index01 * 2], y: this.grid[index01 * 2 + 1]};
const f10 = {x: this.grid[index10 * 2], y: this.grid[index10 * 2 + 1]};
const f11 = {x: this.grid[index11 * 2], y: this.grid[index11 * 2 + 1]};

return {
x: f00.x * (1 - step.x) * (1 - step.y) + f10.x * step.x * (1 - step.y) + f01.x * (1 - step.x) * step.y + f11.x * step.x * step.y,
y: f00.y * (1 - step.x) * (1 - step.y) + f10.y * step.x * (1 - step.y) + f01.y * (1 - step.x) * step.y + f11.y * step.x * step.y
};
}

static IsWidthValid(width: number) {
return width >= 128 && width <= 1024;
}
}
5 changes: 3 additions & 2 deletions src/stores/CatalogStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,9 +350,10 @@ export class CatalogStore {
let minMax = {minX: Number.MAX_VALUE, maxX: -Number.MAX_VALUE, minY: Number.MAX_VALUE, maxY: -Number.MAX_VALUE};
this.imageAssociatedCatalogId.get(frameId)?.forEach(catalogId => {
const coords = this.catalogGLData.get(catalogId);
const count = this.catalogCounts.get(catalogId);
if (coords?.x && coords?.y) {
const minMaxX = minMaxArray(coords.x);
const minMaxY = minMaxArray(coords.y);
const minMaxX = minMaxArray(coords.x.slice(0, count));
const minMaxY = minMaxArray(coords.y.slice(0, count));
if (minMaxX.minVal < minMax.minX) {
minMax.minX = minMaxX.minVal;
}
Expand Down

0 comments on commit 92db739

Please sign in to comment.