Changeset View
Standalone View
binaries/data/mods/public/simulation/components/GuiInterface.js
Show First 20 Lines • Show All 1,634 Lines • ▼ Show 20 Lines | for (let ent of data.snapEntities) | ||||
"ent": ent | "ent": ent | ||||
}; | }; | ||||
} | } | ||||
} | } | ||||
if (minDistEntitySnapData != null) | if (minDistEntitySnapData != null) | ||||
return minDistEntitySnapData; | return minDistEntitySnapData; | ||||
} | } | ||||
elexis: This function is already way too large, move it into a separate function. (Perhaps it would be… | |||||
if (data.snapToEdgeEntities && template.Obstruction && template.Obstruction.Static) | |||||
{ | |||||
let width = template.Obstruction.Static["@depth"] / 2; | |||||
let depth = template.Obstruction.Static["@width"] / 2; | |||||
const maxSide = Math.max(width, depth); | |||||
let templatePos = new Vector2D(data.x, data.z); | |||||
let templateAngle = data.angle ? data.angle : 0.0; | |||||
elexisUnsubmitted Not Done Inline Actions0.0 -> 0 elexis: 0.0 -> 0
new Vector2D(data.x, data.z) -> Vector2D.from3D
data.angle || 0 | |||||
// Get edges of all entities together. | |||||
let allEdges = []; | |||||
for (let ent of data.snapToEdgeEntities) | |||||
allEdges = allEdges.concat(GetObstructionEdges(ent)); | |||||
elexisUnsubmitted Not Done Inline Actionselexis: (reduce if fetishist https://developer.mozilla.org/en… | |||||
KrinkleUnsubmitted Not Done Inline ActionsIn either case, would recommend going for push() instead of concat() so as to not create and discard many intermediate array objects. I assume the reason one would pick concat() here is because one needs to push several at once. There's ways to do that: ES5 JavaScript allEdges.push.apply(allEdges, GetObstructionEdges(…)) ES2015 JavaScript (ES6) allEdges.push(...GetObstructionEdges(…)) Krinkle: In either case, would recommend going for `push()` instead of `concat()` so as to not create… | |||||
const minimalDistanceToSnap = 5.0; | |||||
const getValidEdges = (allEdges, position) => { | |||||
let edges = []; | |||||
for (let edge of allEdges) | |||||
{ | |||||
let signedDistance = edge.normal.dot(position) - edge.normal.dot(edge.begin); | |||||
// Negative signed distance means that the template position | |||||
// is lying behind the edge. | |||||
if (signedDistance < -minimalDistanceToSnap - maxSide || | |||||
signedDistance > minimalDistanceToSnap + maxSide) | |||||
continue; | |||||
let dir1 = edge.begin.clone().sub(edge.end).normalize(); | |||||
let dir2 = new Vector2D(-dir1.x, -dir1.y); | |||||
elexisUnsubmitted Not Done Inline Actionsclone and new Vector2D call can be at least moved out of the loop to avoid re-creation of objects. elexis: clone and new Vector2D call can be at least moved out of the loop to avoid re-creation of… | |||||
let offsetDistance = Math.max( | |||||
dir1.dot(position) - dir1.dot(edge.begin), | |||||
dir2.dot(position) - dir2.dot(edge.end) | |||||
); | |||||
if (offsetDistance > minimalDistanceToSnap + maxSide) | |||||
continue; | |||||
Not Done Inline ActionsMath.Min() ? Stan: Math.Min() ? | |||||
Done Inline ActionsMath.max then :) vladislavbelov: `Math.max` then :) | |||||
// If a projection of the template position on the edge is | |||||
// lying inside the edge then obviously we don't need to | |||||
// account the offset distance. | |||||
if (offsetDistance < 0.0) | |||||
offsetDistance = 0.0; | |||||
edge.signedDistance = signedDistance; | |||||
edge.offsetDistance = offsetDistance; | |||||
edges.push(edge); | |||||
} | |||||
return edges; | |||||
} | |||||
let edges = getValidEdges(allEdges, templatePos); | |||||
if (edges.length) | |||||
{ | |||||
// Pick a base edge, it will be the first axis and fix the angle. | |||||
// We can't just pick an edge by signed distance, because we might have | |||||
// a case when one segment is closer by signed distance than another | |||||
// one but much farther by actual (euclid) distance. | |||||
const compare = (a, b) => { | |||||
const EPS = 1e-3; | |||||
const behindA = a.signedDistance < -EPS; | |||||
const behindB = b.signedDistance < -EPS; | |||||
const scoreA = Math.abs(a.signedDistance) + a.offsetDistance; | |||||
const scoreB = Math.abs(b.signedDistance) + b.offsetDistance; | |||||
if (Math.abs(scoreA - scoreB) < EPS) | |||||
Not Done Inline ActionsOrder important ? if !behindA it's gonna be always different that behindB ? Stan: Order important ? if !behindA it's gonna be always different that behindB ? | |||||
Done Inline ActionsOrder is important :) vladislavbelov: Order is important :) | |||||
{ | |||||
if (behindA != behindB) | |||||
KrinkleUnsubmitted Not Done Inline ActionsUnless type coercion is expected/desired, should probably use !== instead. Krinkle: Unless type coercion is expected/desired, should probably use `!==` instead. | |||||
vladislavbelovAuthorUnsubmitted Done Inline ActionsWhy? We compare two bools. vladislavbelov: Why? We compare two bools. | |||||
return behindA - behindB; | |||||
if (!behindA) | |||||
return a.offsetDistance - b.offsetDistance; | |||||
else | |||||
return -a.signedDistance - -b.signedDistance; | |||||
} | |||||
Not Done Inline ActionsI'm not sure how to write it but I believe you can use array.find() here. Stan: I'm not sure how to write it but I believe you can use array.find() here. | |||||
Done Inline ActionsIt's not a usual find. vladislavbelov: It's not a usual find. | |||||
Not Done Inline ActionsIs there a way to order the edges so that you only have a small part of the array to browse through ? Stan: Is there a way to order the edges so that you only have a small part of the array to browse… | |||||
return scoreA - scoreB; | |||||
}; | |||||
let baseEdge = edges[0]; | |||||
for (let edge of edges) | |||||
if (compare(edge, baseEdge) < 0.0) | |||||
baseEdge = edge; | |||||
// Now we have the normal, we need to determine an angle, | |||||
// which side will be snapped first. | |||||
for (let dir = 0; dir < 4; ++dir) | |||||
{ | |||||
Not Done Inline ActionsCache the Pi values ? Stan: Cache the Pi values ? | |||||
Done Inline ActionsYou mean Math.PI / N? We don't need to cache Math.PI by itself. vladislavbelov: You mean `Math.PI / N`? We don't need to cache `Math.PI` by itself. | |||||
Not Done Inline ActionsYeah that's what I meant. Stan: Yeah that's what I meant. | |||||
const EPS = 1e-3; | |||||
const angleCandidate = baseEdge.angle + dir * Math.PI / 2.0; | |||||
// We need to find a minimal angle difference. | |||||
let difference = Math.abs(angleCandidate - templateAngle); | |||||
difference = Math.min(difference, Math.PI * 2.0 - difference); | |||||
if (difference < Math.PI / 4.0 + EPS) | |||||
{ | |||||
// We need to swap sides for orthogonal cases. | |||||
if (dir % 2 == 0) | |||||
[width, depth] = [depth, width]; | |||||
templateAngle = angleCandidate; | |||||
break; | |||||
} | |||||
Not Done Inline ActionsMaybe you could move the functions out ? Stan: Maybe you could move the functions out ? | |||||
Done Inline ActionsYeah, that was in elexis`s comment. vladislavbelov: Yeah, that was in elexis`s comment. | |||||
} | |||||
// We need a small padding to avoid unnecessary collisions | |||||
// because of loss of accuracy. | |||||
const getPadding = (edge) => { | |||||
const snapPadding = 0.05; | |||||
// We don't need to padding for edges with normals directed inside | |||||
// its entity, as we try to snap from an internal side of the edge. | |||||
return edge.order == 'ccw' ? 0.0 : snapPadding; | |||||
}; | |||||
let distance = baseEdge.normal.dot(templatePos) - baseEdge.normal.dot(baseEdge.begin); | |||||
templatePos.sub(Vector2D.mult(baseEdge.normal, distance - width - getPadding(baseEdge))); | |||||
edges = getValidEdges(allEdges, templatePos); | |||||
if (edges.length > 1) | |||||
elexisUnsubmitted Not Done Inline Actions(perhaps an early return once this hunk is in a function, or moving this into a new function as well) elexis: (perhaps an early return once this hunk is in a function, or moving this into a new function as… | |||||
{ | |||||
let pairedEdges = []; | |||||
for (let edge of edges) | |||||
{ | |||||
const EPS = 1e-3; | |||||
// We have to place a rectangle, so the angle between | |||||
// edges should be 90 degrees. | |||||
if (Math.abs(baseEdge.normal.dot(edge.normal)) > EPS) | |||||
continue; | |||||
let newEdge = { | |||||
'begin': edge.end, | |||||
'end': edge.begin, | |||||
'normal': new Vector2D(-edge.normal.x, -edge.normal.y), | |||||
'signedDistance': -edge.signedDistance, | |||||
'offsetDistance': edge.offsetDistance, | |||||
'order': 'ccw', | |||||
}; | |||||
pairedEdges.push(edge); | |||||
pairedEdges.push(newEdge); | |||||
} | |||||
pairedEdges.sort(compare); | |||||
if (pairedEdges.length) | |||||
{ | |||||
let secondEdge = pairedEdges[0]; | |||||
for (let edge of pairedEdges) | |||||
if (compare(edge, secondEdge) < 0.0) | |||||
secondEdge = edge; | |||||
let distance = secondEdge.normal.dot(templatePos) - secondEdge.normal.dot(secondEdge.begin); | |||||
templatePos.sub(Vector2D.mult(secondEdge.normal, distance - depth - getPadding(secondEdge))); | |||||
} | |||||
} | |||||
return { | |||||
"x": templatePos.x, | |||||
"z": templatePos.y, | |||||
"angle": templateAngle | |||||
}; | |||||
} | |||||
} | |||||
if (template.BuildRestrictions.PlacementType == "shore") | if (template.BuildRestrictions.PlacementType == "shore") | ||||
{ | { | ||||
let angle = GetDockAngle(template, data.x, data.z); | let angle = GetDockAngle(template, data.x, data.z); | ||||
if (angle !== undefined) | if (angle !== undefined) | ||||
return { | return { | ||||
"x": data.x, | "x": data.x, | ||||
"z": data.z, | "z": data.z, | ||||
"angle": angle | "angle": angle | ||||
▲ Show 20 Lines • Show All 329 Lines • Show Last 20 Lines |
This function is already way too large, move it into a separate function. (Perhaps it would be better in a different file as well, since GUIInterface is getting cramped a bit. I understand there is already related code here.)