Difference between revisions of "User:Caron/memo"

From Custom Mario Kart
Jump to navigation Jump to search
(added fix_non_convex method.)
Line 87: Line 87:
 
== Convex Quadrilaterals or not==
 
== Convex Quadrilaterals or not==
 
[[File:Caron is cq.jpg|800px]]
 
[[File:Caron is cq.jpg|800px]]
<br>緑の角度の総和が2πになればよい(または内接円が2π)。4πの場合はConvex Quadrilateralsではない。
+
<br>緑の角度の総和が2πになればよい。4πの場合はConvex Quadrilateralsではない。
  
 
  <nowiki>
 
  <nowiki>
def is_convex(pt1: np.ndarray, pt2: np.ndarray) -> bool:
+
def is_convex(
 +
    pt1: np.ndarray,
 +
    pt2: np.ndarray,
 +
    return_data: bool=False
 +
    )-> Union[bool, Tuple[bool, Optional[np.ndarray]]]:
 
     pos = np.vstack([pt1.reshape(2,2), pt2.reshape(2,2)[::-1]])
 
     pos = np.vstack([pt1.reshape(2,2), pt2.reshape(2,2)[::-1]])
 
     flat = pos.flatten()
 
     flat = pos.flatten()
 
     if flat.shape[0] != np.unique(flat).shape[0]:
 
     if flat.shape[0] != np.unique(flat).shape[0]:
         return False
+
         return False if not return_data else (False, None)
  
 
     vector = np.vstack(
 
     vector = np.vstack(
Line 100: Line 104:
 
         ).T
 
         ).T
 
     res = np.arctan2(vector[1], vector[0])*180/np.pi
 
     res = np.arctan2(vector[1], vector[0])*180/np.pi
     res = (res-np.roll(res, 4))[:4]
+
     res = 180 - (res - np.roll(res, 4))[:4]
     res = np.where(res<0, 360+res, res)
+
     res = np.where(res>=360, res-360, res)
  
     if int(np.sum(res)) == 360:
+
     if not int(np.sum(res)) == 360:
         return True
+
         return False if not return_data else (False, res)
     return False
+
     return True if not return_data else (True, res)
 
</nowiki>
 
</nowiki>
  
Line 116: Line 120:
 
<b>非凸の頂点</b>...簡単。反時計回りで行くなら時計回りになっている点を見つければそれが非凸の頂点。<br>
 
<b>非凸の頂点</b>...簡単。反時計回りで行くなら時計回りになっている点を見つければそれが非凸の頂点。<br>
 
<b>二等分線</b>...非凸の頂点と隣の2点から二等分線を求める<br>
 
<b>二等分線</b>...非凸の頂点と隣の2点から二等分線を求める<br>
<b>移動距離</b>...交点+εの移動
+
<b>移動距離</b>...少しづつ移動させる
  
アルゴリズム:
+
<nowiki>
# 非凸の頂点とその次の頂点をマークし、それぞれを頂点とする角の2等分線(直線式)を計算する
+
def fix_non_convex(pt1: np.ndarray, pt2: np.ndarray):
# 二等分線の交点をマークし、マークした頂点を二等分線に沿って交点 + 追加移動距離εまで移動させる
+
    isconvec, res = is_convex(pt1, pt2, True)
 +
    if isconvec or res is None:
 +
        return pt1, pt2
 +
   
 +
    pos = np.vstack([pt1.reshape(2,2), pt2.reshape(2,2)[::-1]])
 +
    vector = np.vstack(
 +
        [np.roll(pos, 2)-pos, np.roll(pos, -2)-pos]
 +
        )
 +
   
 +
    uvec, vvec = vector[:4], vector[4:]
 +
    a, b = np.linalg.norm(uvec, axis=1), np.linalg.norm(vvec, axis=1)
 +
    apb = a+b
 +
    a_apb, b_apb = (a/apb), (b/apb)
 +
 
 +
    uvec_i2 = np.tile(b_apb, (2,1)).T * uvec
 +
    vvec_i2 = np.tile(a_apb, (2,1)).T * vvec
 +
    vector_i2 = uvec_i2 + vvec_i2
 +
 
 +
    f_index = np.where(res>180)[0][0]
 +
    target_index = [f_index, f_index+1] if f_index != 3 else [f_index, 0]
 +
 
 +
    param = 0.1
 +
    for i in range(1, 20):
 +
        k = pos.copy()
 +
        k[target_index] = k[target_index] + (vector_i2[target_index] * param * i)
 +
        p0, p1 = np.vsplit(k, 2)
 +
        p0  = p0.flatten()
 +
        p1 = p1[::-1].flatten()
 +
        if is_convex(p0, p1):
 +
            break
 +
    return p0, p1
 +
 
 +
</nowiki>
  
 
== Internal nodes ==
 
== Internal nodes ==
 
<b>チェックポイントのパス構造には内部ノードは存在してはいけない</b>(自身のコース製作で経験済み)。CPUとアイテムルートは別にパス関係が木構造になっていてもok.
 
<b>チェックポイントのパス構造には内部ノードは存在してはいけない</b>(自身のコース製作で経験済み)。CPUとアイテムルートは別にパス関係が木構造になっていてもok.

Revision as of 13:38, 19 June 2021

Graphviz

import graphviz # type: ignore

dgraph = graphviz.Digraph(**kwargs)
for i, _ in enumerate(self._data):
    dgraph.node(self._gn(i))
for i, _data in enumerate(self._data):
    label = str(_data[1]-_data[0])
    for nxt in np.unique(_data[8:14])[:-1]: # 255は除外
        dgraph.edge(self._gn(i), self._gn(nxt), label=label)

if render:
    dgraph.render(view=view)
elif view:
    dgraph.view()


Smoothing:Catmull–Clark

faceは不要なのでCatmull-clarkの途中処理まで
not tested yet


counts = round(counts) if isinstance(counts, float) else counts
for _ in range(counts):
    data_size = len(target)
    smoothed = create_new_data(self._sectionname, 2, 2*data_size-1)

    smoothed[::2,:] = target # type: ignore

    # Center position
    smoothed[1::2,0:3] = ((target[:-1,0:3] + target[1:,0:3])/2)
    # Average((cur + center_1 + center_2)/3)
    smoothed[2:-2:2,0:3] = (smoothed[1:-2:2,0:3] + smoothed[3::2,0:3] + smoothed[2:-2:2,0:3])/3

    # update settings
    smoothed = update_settings(
        iter = range(1, len(smoothed)-1),
        old_array=target,
        new_array=smoothed
        )

    # clone array for next iteration.
    target = smoothed.copy()


Smoothing:Spline interpolation

こっちの方が元の曲線に近くフィットしてくれる
not tested yet


pos = target[:, :3].T
m = len(pos[0])

# create knots vector
tck, _ = interpolate.splprep(pos, s=m+np.sqrt(m), k=4)
u_counts = np.linspace(0,1,round(m*counts))

# fitting
fitted = np.vstack(interpolate.splev(u_counts, tck)).T

### update settings: start
data_size = len(fitted)
update_idx = np.zeros(data_size)
# find nearest positions
for idx in range(m):
    old_vec = np.tile(pos.T[idx], (data_size, 1))
    norm = np.linalg.norm(old_vec - fitted, axis=-1)
    update_idx[idx] = np.argmin(norm)
smoothed = create_new_data(self._sectionname, 2, data_size)
smoothed[:,:3] = fitted
# POTI Setting is start at target[3:], but ENPT, ITPT are target[4:].
start = 4 if self._sectionname != 'POTI' else 3 
smoothed[update_idx,start:] = target[:,start:]
smoothed = update_settings(
    iter=range(1, m),
    old_array=target,
    new_array=smoothed,
    spline_index=update_idx
)


Convex Quadrilaterals or not

Caron is cq.jpg
緑の角度の総和が2πになればよい。4πの場合はConvex Quadrilateralsではない。

def is_convex(
    pt1: np.ndarray,
    pt2: np.ndarray,
    return_data: bool=False
    )-> Union[bool, Tuple[bool, Optional[np.ndarray]]]:
    pos = np.vstack([pt1.reshape(2,2), pt2.reshape(2,2)[::-1]])
    flat = pos.flatten()
    if flat.shape[0] != np.unique(flat).shape[0]:
        return False if not return_data else (False, None)

    vector = np.vstack(
        [np.roll(pos, 2)-pos, np.roll(pos, -2)-pos]
        ).T
    res = np.arctan2(vector[1], vector[0])*180/np.pi
    res = 180 - (res - np.roll(res, 4))[:4]
    res = np.where(res>=360, res-360, res)

    if not int(np.sum(res)) == 360:
        return False if not return_data else (False, res)
    return True if not return_data else (True, res)


Fix Non-convex Quadrilaterals

これでいけそう
Caron cq f image.png

非凸の頂点...簡単。反時計回りで行くなら時計回りになっている点を見つければそれが非凸の頂点。
二等分線...非凸の頂点と隣の2点から二等分線を求める
移動距離...少しづつ移動させる

def fix_non_convex(pt1: np.ndarray, pt2: np.ndarray):
    isconvec, res = is_convex(pt1, pt2, True)
    if isconvec or res is None:
        return pt1, pt2
    
    pos = np.vstack([pt1.reshape(2,2), pt2.reshape(2,2)[::-1]])
    vector = np.vstack(
        [np.roll(pos, 2)-pos, np.roll(pos, -2)-pos]
        )
    
    uvec, vvec = vector[:4], vector[4:]
    a, b = np.linalg.norm(uvec, axis=1), np.linalg.norm(vvec, axis=1)
    apb = a+b
    a_apb, b_apb = (a/apb), (b/apb)

    uvec_i2 = np.tile(b_apb, (2,1)).T * uvec
    vvec_i2 = np.tile(a_apb, (2,1)).T * vvec
    vector_i2 = uvec_i2 + vvec_i2

    f_index = np.where(res>180)[0][0]
    target_index = [f_index, f_index+1] if f_index != 3 else [f_index, 0]

    param = 0.1
    for i in range(1, 20):
        k = pos.copy()
        k[target_index] = k[target_index] + (vector_i2[target_index] * param * i)
        p0, p1 = np.vsplit(k, 2)
        p0  = p0.flatten()
        p1 = p1[::-1].flatten()
        if is_convex(p0, p1):
            break
    return p0, p1


Internal nodes

チェックポイントのパス構造には内部ノードは存在してはいけない(自身のコース製作で経験済み)。CPUとアイテムルートは別にパス関係が木構造になっていてもok.